def uninstallPackage(self, productId, force=False, deleteFiles=True): depotId = self._depotBackend._depotId logger.info( u"=================================================================================================" ) logger.notice(u"Uninstalling product '%s' on depot '%s'" % (productId, depotId)) try: productId = forceProductIdFunc(productId) force = forceBool(force) deleteFiles = forceBool(deleteFiles) dataBackend = self._depotBackend._context depot = dataBackend.host_getObjects(type='OpsiDepotserver', id=depotId)[0] productOnDepots = dataBackend.productOnDepot_getObjects( depotId=depotId, productId=productId) try: productOnDepot = productOnDepots[0] except IndexError: raise BackendBadValueError( "Product '%s' is not installed on depot '%s'" % (productId, depotId)) if productOnDepot.getLocked(): logger.notice(u"Product '{}' currently locked on depot '{}'", productId, depotId) if not force: raise BackendTemporaryError( u"Product '%s' currently locked on depot '%s'" % (productId, depotId)) logger.warning(u"Uninstallation of locked product forced") logger.notice(u"Locking product '%s' on depot '%s'" % (productId, depotId)) productOnDepot.setLocked(True) dataBackend.productOnDepot_updateObject(productOnDepot) logger.debug("Deleting product '{}'", productId) if deleteFiles: if not depot.depotLocalUrl.startswith('file:///'): raise BackendBadValueError( u"Value '%s' not allowed for depot local url (has to start with 'file:///')" % depot.depotLocalUrl) for element in os.listdir(depot.depotLocalUrl[7:]): if element.lower() == productId.lower(): clientDataDir = os.path.join(depot.depotLocalUrl[7:], element) logger.info("Deleting client data dir '{}'", clientDataDir) removeDirectory(clientDataDir) dataBackend.productOnDepot_deleteObjects(productOnDepot) except Exception as uninstallError: logger.logException(uninstallError) raise BackendError( u"Failed to uninstall product '%s' on depot '%s': %s" % (productId, depotId, uninstallError))
def create(self, fileList, baseDir='.', dereference=False): try: fileList = forceUnicodeList(fileList) baseDir = os.path.abspath(forceFilename(baseDir)) dereference = forceBool(dereference) if not os.path.isdir(baseDir): raise IOError(u"Base dir '%s' not found" % baseDir) command = u'%s --create --quiet --verbose --format crc' % System.which( 'cpio') if dereference: command += ' --dereference' if self._compression == 'gzip': if self.pigz_detected: command += ' | %s --rsyncable' % System.which('pigz') else: command += ' | %s --rsyncable' % System.which('gzip') elif self._compression == 'bzip2': command += ' | %s' % System.which('bzip2') command += ' > "%s"' % self._filename self._create(fileList, baseDir, command) except Exception as e: raise RuntimeError(u"Failed to create archive '%s': %s" % (self._filename, e))
def __init__(self, id, type=u'', title=u'', **args): MessageSubject.__init__(self, id, type, title, **args) self.reset() self._callbacks = [] try: self._multiValue = forceBool(args['multiValue']) except KeyError: pass try: self._choices = forceUnicodeList(args['choices']) except KeyError: pass try: self._selectedIndexes = forceIntList(args['selectedIndexes']) except KeyError: pass try: self._callbacks = args['callbacks'] except KeyError: pass logger.debug(u"ChoiceSubject '%s' created" % self._id)
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 addEvent(self, title, description='', isError=False, category=None, durationEvent=False, start=None, end=None): # pylint: disable=too-many-arguments if self._stopped: return -1 with self._db_lock, self._sql.session() as session: try: if category: category = forceUnicode(category) if not start: start = timestamp() start = forceOpsiTimestamp(start) if end: end = forceOpsiTimestamp(end) durationEvent = True event = { 'title': forceUnicode(title), 'category': category, 'description': forceUnicode(description), 'isError': forceBool(isError), 'durationEvent': forceBool(durationEvent), 'start': start, 'end': end, } try: return self._sql.insert(session, 'EVENT', event) except sqlite3.DatabaseError as db_error: logger.error( "Failed to add event '%s': %s, recreating database", title, db_error) self._sql.delete_db() self._createDatabase(delete_existing=True) return self._sql.insert(session, 'EVENT', event) except Exception as add_error: # pylint: disable=broad-except logger.error("Failed to add event '%s': %s", title, add_error) return -1
def setDeflate(self, deflate): if not self._connected: raise OpsiConnectionError(u'Not connected') logger.warning("Call to deprecated method 'setDeflate'. " "This method will be removed in the future. " "Please use the method 'setCompression' instead.") if forceBool(deflate): self.setCompression('deflate') else: self.setCompression(False)
def __init__(self, id, type=u'', title=u'', **args): MessageSubject.__init__(self, id, type, title, **args) self.reset() self._fireAlways = True self._endChangable = True try: self._end = forceInt(args['end']) if self._end < 0: self._end = 0 except KeyError: pass try: self._percent = args['percent'] except KeyError: pass try: self._state = args['state'] except KeyError: pass try: self._timeStarted = args['timeStarted'] except KeyError: pass try: self._timeSpend = args['timeSpend'] except KeyError: pass try: self._timeLeft = args['timeLeft'] except KeyError: pass try: self._timeFired = args['timeFired'] except KeyError: pass try: self._speed = args['speed'] except KeyError: pass try: self._fireAlways = forceBool(args['fireAlways']) except KeyError: pass logger.debug(u"ProgressSubject {0!r} created", self._id)
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 __init__(self, **kwargs): self._name = 'dhcpd' ConfigDataBackend.__init__(self, **kwargs) self._dhcpdConfigFile = System.Posix.locateDHCPDConfig( u'/etc/dhcp3/dhcpd.conf') self._reloadConfigCommand = '/usr/bin/sudo {command}'.format( command=System.Posix.getDHCPDRestartCommand( default='/etc/init.d/dhcp3-server restart')) self._fixedAddressFormat = u'IP' self._defaultClientParameters = { 'next-server': socket.gethostbyname(getfqdn()), 'filename': u'linux/pxelinux.0' } self._dhcpdOnDepot = False # Parse arguments for (option, value) in kwargs.items(): option = option.lower() if option == 'dhcpdconfigfile': self._dhcpdConfigFile = value elif option == 'reloadconfigcommand': self._reloadConfigCommand = value elif option == 'defaultclientparameters': self._defaultClientParameters = forceDict(value) elif option == 'fixedaddressformat': if value not in (u'IP', u'FQDN'): raise BackendBadValueError( u"Bad value '%s' for fixedAddressFormat, possible values are %s" % (value, u', '.join(('IP', 'FQDN')))) self._fixedAddressFormat = value elif option == 'dhcpdondepot': self._dhcpdOnDepot = forceBool(value) if self._defaultClientParameters.get( 'next-server' ) and self._defaultClientParameters['next-server'].startswith(u'127'): raise BackendBadValueError( u"Refusing to use ip address '%s' as default next-server" % self._defaultClientParameters['next-server']) self._dhcpdConfFile = DHCPDConfFile(self._dhcpdConfigFile) self._reloadEvent = threading.Event() self._reloadEvent.set() self._reloadLock = threading.Lock() self._reloadThread = None self._depotId = forceHostId(getfqdn()) self._opsiHostKey = None self._depotConnections = {}
def _configureHostcontrolBackend(backend, kwargs): """ Configure `backend` to the values given in `kwargs`. Keys in `kwargs` will be treated as lowercase. Supported keys are 'broadcastaddresses', 'hostrpctimeout', \ 'maxconnections' opsiclientdport' and 'resolvehostaddress'. Unrecognized options will be ignored. :type backend: HostControlBackend or HostControlSafeBackend :type kwargs: dict """ for option, value in kwargs.items(): option = option.lower() if option == 'opsiclientdport': backend._opsiclientdPort = forceInt(value) elif option == 'hostrpctimeout': backend._hostRpcTimeout = forceInt(value) elif option == 'resolvehostaddress': backend._resolveHostAddress = forceBool(value) elif option == 'maxconnections': backend._maxConnections = forceInt(value) elif option == 'broadcastaddresses': try: backend._broadcastAddresses = forceDict(value) except ValueError: # This is an old-style configuraton. Old default # port was 12287 so we assume this as the default # and convert everything to the new format. backend._broadcastAddresses = { bcAddress: (12287, ) for bcAddress in forceUnicodeList(value) } logger.warning( "Your hostcontrol backend configuration uses the old " "format for broadcast addresses. The new format " "allows to also set a list of ports to send the " "broadcast to.\nPlease use this new " "value in the future: {0!r}", backend._broadcastAddresses) newAddresses = { bcAddress: tuple(forceInt(port) for port in ports) for bcAddress, ports in backend._broadcastAddresses.items() } backend._broadcastAddresses = newAddresses if backend._maxConnections < 1: backend._maxConnections = 1
def _parseCompressionValue(compression): if isinstance(compression, bool): return compression else: value = forceUnicode(compression) value = value.strip() value = value.lower() if value in ('true', 'false'): return forceBool(value) elif value == 'gzip': return _GZIP_COMPRESSION elif value == 'deflate': return _DEFLATE_COMPRESSION else: return False
def __init__(self, **kwargs): self._database = ":memory:" self._synchronous = True self._databaseCharset = 'utf8' for (option, value) in kwargs.items(): option = option.lower() if option == 'database': self._database = forceFilename(value) elif option == 'synchronous': self._synchronous = forceBool(value) elif option == 'databasecharset': self._databaseCharset = str(value) self._connection = None self._cursor = None logger.debug(u'SQLite created: %s' % self)
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 depot_getMD5Sum(self, filename, forceCalculation=False): checksum = None try: if not forceBool(forceCalculation): hashFile = filename + '.md5' try: with open(hashFile) as fileHandle: checksum = fileHandle.read() logger.info(u"Using pre-calculated MD5sum from '{0}'.", hashFile) except (OSError, IOError): pass if not checksum: checksum = md5sum(filename) logger.info(u"MD5sum of file '{0}' is '{1}'", filename, checksum) return checksum except Exception as error: raise BackendIOError(u"Failed to get md5sum: %s" % error)
def __init__(self, name, baseUrl, dirs=[], username=u"", password=u"", authcertfile=u"", authkeyfile="", opsiDepotId=None, autoInstall=False, autoUpdate=True, autoSetup=False, proxy=None, excludes=[], includes=[], active=False): self.name = forceUnicode(name) self.baseUrl = forceUnicode(baseUrl) self.dirs = forceUnicodeList(dirs) self.excludes = excludes self.includes = includes self.username = forceUnicode(username) self.password = forceUnicode(password) self.authcertfile = forceUnicode(authcertfile) self.authkeyfile = forceUnicode(authkeyfile) self.autoInstall = autoInstall self.autoUpdate = autoUpdate self.autoSetup = autoSetup self.opsiDepotId = opsiDepotId self.onlyDownload = None self.inheritProductProperties = None self.description = '' self.active = forceBool(active) self.proxy = None if proxy: self.proxy = proxy if self.baseUrl.startswith('webdav'): self.baseUrl = u'http%s' % self.baseUrl[6:]
def get(self, name, default=None): # pylint: disable=too-many-return-statements,too-many-branches name = forceUnicode(name) if name == 'user_logged_in': if RUNNING_ON_WINDOWS: for session in System.getActiveSessionInformation(): if session["UserName"] != OPSI_SETUP_USER_NAME: return True return False if RUNNING_ON_LINUX: for proc in psutil.process_iter(): try: env = proc.environ() if env.get("DISPLAY") and proc.uids()[0] >= 1000: return True except psutil.AccessDenied: pass return False if RUNNING_ON_DARWIN: # TODO return True return False if name == 'products_cached': return self._state.get('product_cache_service', {}).get('products_cached', default) if name == 'config_cached': return self._state.get('config_cache_service', {}).get('config_cached', default) if "cancel_counter" in name: return self._state.get(name, 0) if name == 'installation_pending': return forceBool(self._state.get('installation_pending', False)) try: return self._state[name] except KeyError: logger.warning("Unknown state name '%s', returning default '%s'", name, default) return default
def __init__(self, readBackend, writeBackend, newServerId=None, oldServerId=None, cleanupFirst=True): self.__readBackend = readBackend self.__writeBackend = writeBackend self._extendedReadBackend = ExtendedConfigDataBackend( self.__readBackend) self._extendedWriteBackend = ExtendedConfigDataBackend( self.__writeBackend) self.__newServerId = None self.__oldServerId = None self.__cleanupFirst = forceBool(cleanupFirst) self.__strict = False self.__serverIds = [] self.__depotIds = [] self.__clientIds = [] self.__groupIds = [] self.__productIds = [] if newServerId: self.__newServerId = forceHostId(newServerId) if oldServerId: self.__oldServerId = forceHostId(oldServerId) self.__overallProgressSubject = ProgressSubject( id=u'overall_replication', title=u'Replicating', end=100, fireAlways=True) self.__currentProgressSubject = ProgressSubject( id=u'current_replication', fireAlways=True)
def __init__(self, address, **kwargs): """ Backend for JSON-RPC access to another opsi service. :param compression: Specify compression usage. Can be a boolean \ or the strings 'gzip' or 'deflate' in case a specific compression is desired. :type compression: bool or str :param deflate: Specify if deflate compression should be used for requests. \ Deprecated: Use keyword 'compression' instead. :type deflate: bool """ self._name = 'jsonrpc' Backend.__init__(self, **kwargs) self._application = 'opsi jsonrpc module version %s' % __version__ self._sessionId = None self._compression = False self._connectOnInit = True self._connected = False self._retryTime = 5 self._host = None self._port = None self._baseUrl = u'/rpc' self._protocol = 'https' self._socketTimeout = None self._connectTimeout = 30 self._connectionPoolSize = 2 self._interface = None self._rpcId = 0 self._rpcIdLock = threading.Lock() self._async = False self._rpcQueue = None self._rpcQueuePollingTime = 0.01 self._rpcQueueSize = 10 self._serverCertFile = None self._caCertFile = None self._verifyServerCert = False self._verifyServerCertByCa = False self._verifyByCaCertsFile = None self._proxyURL = None if not self._username: self._username = u'' if not self._password: self._password = u'' retry = True for (option, value) in kwargs.items(): option = option.lower() if option == 'application': self._application = str(value) elif option == 'sessionid': self._sessionId = str(value) elif option == 'deflate': if forceBool(value): self.setCompression('deflate') else: self.setCompression(False) elif option == 'compression': self._compression = self._parseCompressionValue(value) elif option == 'connectoninit': self._connectOnInit = forceBool(value) elif option == 'connecttimeout' and value is not None: self._connectTimeout = forceInt(value) elif option == 'connectionpoolsize' and value is not None: self._connectionPoolSize = forceInt(value) elif option in ('timeout', 'sockettimeout') and value is not None: self._socketTimeout = forceInt(value) elif option == 'retry': retry = forceBool(value) elif option == 'retrytime': self._retryTime = forceInt(value) elif option == 'rpcqueuepollingtime': self._rpcQueuePollingTime = forceFloat(value) elif option == 'rpcqueuesize': self._rpcQueueSize = forceInt(value) elif option == 'servercertfile' and value is not None: self._serverCertFile = forceFilename(value) elif option == 'verifyservercert': self._verifyServerCert = forceBool(value) elif option == 'cacertfile' and value is not None: self._caCertFile = forceFilename(value) elif option == 'verifyservercertbyca': self._verifyServerCertByCa = forceBool(value) elif option == 'proxyurl' and value is not None: logger.debug(u"ProxyURL detected: '%s'" % value) self._proxyURL = forceUnicode(value) if not retry: self._retryTime = 0 if self._password: logger.addConfidentialString(self._password) self._processAddress(address) self._connectionPool = getSharedConnectionPool( scheme=self._protocol, host=self._host, port=self._port, socketTimeout=self._socketTimeout, connectTimeout=self._connectTimeout, retryTime=self._retryTime, maxsize=self._connectionPoolSize, block=True, verifyServerCert=self._verifyServerCert, serverCertFile=self._serverCertFile, caCertFile=self._caCertFile, verifyServerCertByCa=self._verifyServerCertByCa, proxyURL=self._proxyURL) if self._connectOnInit: self.connect()
def __init__(self, prior, posterior, fulfilled=False): self.prior = forceInt(prior) self.posterior = forceInt(posterior) self.fulfilled = forceBool(fulfilled)
def __init__(self, packageSourceDir, tempDir=None, customName=None, customOnly=False, packageFileDestDir=None, format='cpio', compression='gzip', dereference=False): self.packageSourceDir = os.path.abspath( forceFilename(packageSourceDir)) if not os.path.isdir(self.packageSourceDir): raise IOError(u"Package source directory '%s' not found" % self.packageSourceDir) tempDir = tempDir or DEFAULT_TMP_DIR self.tempDir = os.path.abspath(forceFilename(tempDir)) if not os.path.isdir(self.tempDir): raise IOError(u"Temporary directory '%s' not found" % self.tempDir) self.customName = None if customName: self.customName = forcePackageCustomName(customName) self.customOnly = forceBool(customOnly) if format: if format not in (u'cpio', u'tar'): raise ValueError(u"Format '%s' not supported" % format) self.format = format else: self.format = u'cpio' if not compression: self.compression = None else: if compression not in (u'gzip', u'bzip2'): raise ValueError(u"Compression '%s' not supported" % compression) self.compression = compression self.dereference = forceBool(dereference) if not packageFileDestDir: packageFileDestDir = self.packageSourceDir packageFileDestDir = os.path.abspath(forceFilename(packageFileDestDir)) if not os.path.isdir(packageFileDestDir): raise IOError(u"Package destination directory '%s' not found" % packageFileDestDir) packageControlFile = os.path.join(self.packageSourceDir, u'OPSI', u'control') if customName and os.path.exists( os.path.join(self.packageSourceDir, u'OPSI.%s' % customName, u'control')): packageControlFile = os.path.join(self.packageSourceDir, u'OPSI.%s' % customName, u'control') self.packageControlFile = PackageControlFile(packageControlFile) self.packageControlFile.parse() customName = u'' if self.customName: customName = u'~%s' % self.customName self.packageFile = os.path.join( packageFileDestDir, u"%s_%s-%s%s.opsi" % (self.packageControlFile.getProduct().id, self.packageControlFile.getProduct().productVersion, self.packageControlFile.getProduct().packageVersion, customName)) self.tmpPackDir = os.path.join(self.tempDir, u'.opsi.pack.%s' % randomString(5))
def findFiles(directory, prefix=u'', excludeDir=None, excludeFile=None, includeDir=None, includeFile=None, returnDirs=True, returnLinks=True, followLinks=False, repository=None): directory = forceFilename(directory) prefix = forceUnicode(prefix) if excludeDir: if not isRegularExpressionPattern(excludeDir): excludeDir = re.compile(forceUnicode(excludeDir)) else: excludeDir = None if excludeFile: if not isRegularExpressionPattern(excludeFile): excludeFile = re.compile(forceUnicode(excludeFile)) else: excludeFile = None if includeDir: if not isRegularExpressionPattern(includeDir): includeDir = re.compile(forceUnicode(includeDir)) else: includeDir = None if includeFile: if not isRegularExpressionPattern(includeFile): includeFile = re.compile(forceUnicode(includeFile)) else: includeFile = None returnDirs = forceBool(returnDirs) returnLinks = forceBool(returnLinks) followLinks = forceBool(followLinks) if repository: islink = repository.islink isdir = repository.isdir listdir = repository.listdir else: islink = os.path.islink isdir = os.path.isdir listdir = os.listdir files = [] for entry in listdir(directory): if isinstance(entry, str): # TODO how to handle this with Python 3? logger.error( u"Bad filename '%s' found in directory '%s', skipping entry!" % (unicode(entry, 'ascii', 'replace'), directory)) continue pp = os.path.join(prefix, entry) dp = os.path.join(directory, entry) isLink = False if islink(dp): isLink = True if not returnLinks and not followLinks: continue if isdir(dp) and (not isLink or followLinks): if excludeDir and re.search(excludeDir, entry): logger.debug(u"Excluding dir '%s' and containing files" % entry) continue if includeDir: if not re.search(includeDir, entry): continue logger.debug(u"Including dir '%s' and containing files" % entry) if returnDirs: files.append(pp) files.extend( findFiles(directory=dp, prefix=pp, excludeDir=excludeDir, excludeFile=excludeFile, includeDir=includeDir, includeFile=includeFile, returnDirs=returnDirs, returnLinks=returnLinks, followLinks=followLinks, repository=repository)) continue if excludeFile and re.search(excludeFile, entry): if isLink: logger.debug(u"Excluding link '%s'" % entry) else: logger.debug(u"Excluding file '%s'" % entry) continue if includeFile: if not re.search(includeFile, entry): continue if isLink: logger.debug(u"Including link '%s'" % entry) else: logger.debug(u"Including file '%s'" % entry) files.append(pp) return files
def __init__(self, host, port, socketTimeout=None, connectTimeout=None, retryTime=0, maxsize=1, block=False, reuseConnection=False, verifyServerCert=False, serverCertFile=None, caCertFile=None, verifyServerCertByCa=False, proxyURL=None): self.host = forceUnicode(host) self.port = forceInt(port) self.socketTimeout = forceInt(socketTimeout or 0) self.connectTimeout = forceInt(connectTimeout or 0) self.retryTime = forceInt(retryTime) self.block = forceBool(block) self.reuseConnection = forceBool(reuseConnection) self.proxyURL = forceUnicode(proxyURL or u"") self.pool = None self.usageCount = 1 self.num_connections = 0 self.num_requests = 0 self.httplibDebugLevel = 0 self.peerCertificate = None self.serverVerified = False self.verifyServerCert = False self.serverCertFile = None self.caCertFile = None self.verifyServerCertByCa = False if isinstance(self, HTTPSConnectionPool): if self.host in ('localhost', '127.0.0.1'): self.serverVerified = True logger.debug(u"No host verification for localhost") else: if caCertFile: self.caCertFile = forceFilename(caCertFile) self.verifyServerCertByCa = forceBool(verifyServerCertByCa) if self.verifyServerCertByCa: if not self.caCertFile: raise ValueError( u"Server certificate verfication by CA enabled but no CA cert file given" ) logger.info( u"Server certificate verfication by CA file '%s' enabled for host '%s'" % (self.caCertFile, self.host)) else: self.verifyServerCert = forceBool(verifyServerCert) if serverCertFile: self.serverCertFile = forceFilename(serverCertFile) if self.verifyServerCert: if not self.serverCertFile: raise ValueError( u"Server verfication enabled but no server cert file given" ) logger.info( u"Server verfication by server certificate enabled for host '%s'" % self.host) self.adjustSize(maxsize)
def testForceBoolWithTrueValues(value): assert forceBool(value) is True
def replicate(self, serverIds=[], depotIds=[], clientIds=[], groupIds=[], productIds=[], productTypes=[], audit=True, license=True): ''' Replicate (a part) of a opsi configuration database An empty list passed as a param means: replicate all known None as the only element of a list means: replicate none ''' serverIds = forceList(serverIds) depotIds = forceList(depotIds) clientIds = forceList(clientIds) groupIds = forceList(serverIds) productIds = forceList(productIds) productTypes = forceList(productTypes) audit = forceBool(audit) license = forceBool(license) logger.info( u"Replicating: serverIds={serverIds}, depotIds={depotIds}, " u"clientIds={clientIds}, groupIds={groupIds}, " u"productIds={productIds}, productTypes={productTypes}, " u"audit: {audit}, license: {license}".format(**locals())) rb = self._extendedReadBackend wb = self.__writeBackend aric = wb.backend_getOptions().get( 'additionalReferentialIntegrityChecks', True) if self.__strict: wb = self._extendedWriteBackend else: wb.backend_setOptions( {'additionalReferentialIntegrityChecks': False}) try: if serverIds or depotIds or clientIds: if not serverIds: serverIds = rb.host_getIdents(type='OpsiConfigserver', returnType=list) if not depotIds: depotIds = rb.host_getIdents(type='OpsiDepotserver', returnType=list) if not clientIds: clientIds = rb.host_getIdents(type='OpsiClient', returnType=list) hostIds = set() for serverId in serverIds: hostIds.add(serverId) for depotId in depotIds: hostIds.add(depotId) for clientId in clientIds: hostIds.add(clientId) self.__overallProgressSubject.reset() end = self._getNumberOfObjectClassesToProcess(audit, license) if self.__cleanupFirst: end += 1 if self.__newServerId: end += 1 self.__overallProgressSubject.setEnd(end) if self.__cleanupFirst: wb.backend_deleteBase() self.__overallProgressSubject.addToState(1) wb.backend_createBase() productOnDepots = [] if depotIds: productOnDepots = rb.productOnDepot_getObjects( depotId=depotIds, productId=productIds, productType=productTypes) productIdsOnDepot = set() for productOnDepot in productOnDepots: productIdsOnDepot.add(productOnDepot.productId) if productIdsOnDepot: if not productIds: productIds = list(productIdsOnDepot) else: newProductIds = [] for productId in productIds: if productId in productIdsOnDepot: newProductIds.append(productId) productIds = newProductIds auditClasses = set([ 'AuditHardware', 'AuditSoftware', 'AuditHardwareOnHost', 'AuditSoftwareOnClient' ]) licenseClasses = set([ 'LicenseContract', 'SoftwareLicense', 'LicensePool', 'SoftwareLicenseToLicensePool', 'LicenseOnClient', 'AuditSoftwareToLicensePool' ]) configServer = None depotServers = [] for objClass in self.OBJECT_CLASSES: if not audit and objClass in auditClasses: continue if not license and objClass in licenseClasses: continue subClasses = [None] if objClass == 'Host': subClasses = [ 'OpsiConfigserver', 'OpsiDepotserver', 'OpsiClient' ] methodPrefix = eval("%s.backendMethodPrefix" % objClass) self.__overallProgressSubject.setMessage(u"Replicating %s" % objClass) self.__currentProgressSubject.setTitle(u"Replicating %s" % objClass) for subClass in subClasses: filter = {} if subClass == 'OpsiConfigserver': filter = {'type': subClass, 'id': serverIds} elif subClass == 'OpsiDepotserver': filter = {'type': subClass, 'id': depotIds} elif subClass == 'OpsiClient': filter = {'type': subClass, 'id': clientIds} elif objClass == 'Group': filter = {'type': subClass, 'id': groupIds} elif objClass == 'Product': filter = {'type': subClass, 'id': productIds} elif objClass == 'ProductOnClient': filter = { 'productType': productTypes, 'productId': productIds, 'clientId': clientIds } elif objClass == 'ProductOnDepot': filter = { 'productType': productTypes, 'productId': productIds, 'depotId': depotIds } elif objClass == 'ProductDependency': filter = {'productId': productIds} elif objClass == 'ProductProperty': filter = {'productId': productIds} elif objClass == 'ProductPropertyState': filter = { 'productId': productIds, 'objectId': forceList(hostIds) } elif objClass == 'ConfigState': filter = {'objectId': forceList(hostIds)} elif objClass == 'ObjectToGroup': if productIds and hostIds: objectIds = productIds + forceList(hostIds) else: objectIds = [] filter = {'objectId': objectIds} elif objClass == 'LicenseOnClient': filter = {'clientId': clientIds} logger.notice("Replicating class '%s', filter: %s" % (objClass, filter)) if not subClass: subClass = objClass Class = eval(subClass) self.__currentProgressSubject.reset() self.__currentProgressSubject.setMessage( u"Reading objects") self.__currentProgressSubject.setEnd(1) objs = [] if objClass == 'ProductOnDepot' and productOnDepots: objs = productOnDepots else: meth = '%s_getObjects' % Class.backendMethodPrefix meth = getattr(rb, meth) objs = meth(**filter) self.__currentProgressSubject.addToState(1) if objClass == 'Group': # Sort groups sortedObjs = [] groupIds = [] while True: notAddedObjs = [] for obj in objs: if not obj.getParentGroupId( ) or obj.getParentGroupId() in groupIds: if not obj.getParentGroupId(): logger.debug( u"Adding group '%s' without parent group set" % obj) else: logger.debug( u"Adding group '%s' with parent group '%s' already added" % (obj, obj.getParentGroupId())) sortedObjs.append(obj) groupIds.append(obj.getId()) else: logger.debug( u"Cannot add group '%s' parent group '%s' not added yet" % (obj, obj.getParentGroupId())) notAddedObjs.append(obj) if not notAddedObjs: break if len(notAddedObjs) == len(objs): for obj in notAddedObjs: logger.error(u"Failed to add group: %s" % obj) break objs = notAddedObjs objs = sortedObjs self.__currentProgressSubject.reset() self.__currentProgressSubject.setMessage( u"Writing objects") if subClass == 'OpsiConfigserver' and objs: configServer = objs[0] depotServers.extend(objs) if subClass == 'OpsiDepotserver': depotServers.extend(objs) if self.__strict: self.__currentProgressSubject.setEnd(1) meth = '%s_createObjects' % Class.backendMethodPrefix meth = getattr(wb, meth) meth(objs) self.__currentProgressSubject.addToState(1) else: self.__currentProgressSubject.setEnd(len(objs)) meth = '%s_insertObject' % Class.backendMethodPrefix meth = getattr(wb, meth) for obj in objs: try: meth(obj) except Exception as e: logger.logException(e, LOG_DEBUG) logger.error( u"Failed to replicate object %s: %s" % (obj, e)) self.__currentProgressSubject.addToState(1) self.__currentProgressSubject.setState(len(objs)) self.__overallProgressSubject.addToState(1) if self.__newServerId: self.__currentProgressSubject.reset() self.__currentProgressSubject.setMessage(u"Renaming server") self.__currentProgressSubject.setTitle(u"Renaming server") self.__currentProgressSubject.setEnd(1) if not self.__oldServerId: if configServer: self.__oldServerId = configServer.id elif depotServers: self.__oldServerId = depotServers[0].id else: logger.error(u"No config/depot servers found") if self.__oldServerId and self.__oldServerId != self.__newServerId: logger.notice( u"Renaming config server {0!r} to {1!r}".format( self.__oldServerId, self.__newServerId)) renamingBackend = wb try: renamingBackend.host_renameOpsiDepotserver() except TypeError: pass # Missing arguments but method exists except AttributeError: # Missing the method - need to use extended backend renamingBackend = self._extendedWriteBackend renamingBackend.host_renameOpsiDepotserver( oldId=self.__oldServerId, newId=self.__newServerId) newDepots = [] for depot in renamingBackend.host_getObjects( type='OpsiDepotserver'): hash = depot.toHash() del hash['type'] if depot.id == self.__newServerId: newDepots.append(OpsiConfigserver.fromHash(hash)) else: newDepots.append(OpsiDepotserver.fromHash(hash)) renamingBackend.host_createObjects(newDepots) self.__overallProgressSubject.addToState(1) finally: wb.backend_setOptions( {'additionalReferentialIntegrityChecks': aric})
def cleanupBackend(backend=None): """ Clean up data from your backends. This method uses different cleanup methods to ensure that no obsolete data is present in your backend. :param backend: the backend to check. If ``None`` this will create a \ BackendManager from default paths. :type backend: OPSI.Backend.Backend """ def usesMysqlBackend(): LOGGER.notice(u"Parsing dispatch.conf") bdc = BackendDispatchConfigFile( u'/etc/opsi/backendManager/dispatch.conf') dispatchConfig = bdc.parse() for entry in dispatchConfig: (regex, backends) = entry if not re.search(regex, u'backend_createBase'): continue if 'mysql' in backends: return True return False LOGGER.debug("Cleaning backend chunk size: {0}".format(_CHUNK_SIZE)) if backend is None: backend = BackendManager( dispatchConfigFile=u'/etc/opsi/backendManager/dispatch.conf', backendConfigDir=u'/etc/opsi/backends', extensionConfigDir=u'/etc/opsi/backendManager/extend.d', depotbackend=False) try: if usesMysqlBackend(): LOGGER.notice( u"Mysql-backend detected. Trying to cleanup mysql-backend first" ) # ToDo: backendConfigFile should be as dynamic as possible # What if we have 2 mysql backends set up? cleanUpMySQL() except Exception as error: LOGGER.warning(error) LOGGER.notice(u"Cleaning up groups") cleanUpGroups(backend) LOGGER.notice(u"Cleaning up products") cleanUpProducts(backend) LOGGER.debug(u'Getting current depots...') depotIds = set(depot.id for depot in backend.host_getObjects( type=["OpsiConfigserver", "OpsiDepotserver"])) # pylint: disable=maybe-no-member LOGGER.debug(u'Depots are: {0}'.format(depotIds)) LOGGER.debug(u'Getting current products...') productIdents = set( product.getIdent(returnType='unicode') for product in backend.product_getObjects()) LOGGER.debug(u'Product idents are: {0}'.format(productIdents)) LOGGER.notice(u"Cleaning up product on depots") cleanUpProductOnDepots(backend, depotIds, productIdents) LOGGER.notice(u"Cleaning up product on clients") cleanUpProductOnClients(backend) LOGGER.notice(u"Cleaning up product properties") productPropertyIdents = set() deleteProductProperties = [] productPropertiesToCleanup = {} for productProperty in backend.productProperty_getObjects(): # pylint: disable=maybe-no-member productIdent = u"%s;%s;%s" % (productProperty.productId, productProperty.productVersion, productProperty.packageVersion) if not productProperty.editable and productProperty.possibleValues: productPropertyIdent = u"%s;%s" % (productIdent, productProperty.propertyId) productPropertiesToCleanup[productPropertyIdent] = productProperty if productIdent not in productIdents: LOGGER.info( u"Marking productProperty %s of non existent product '%s' for deletion" % (productProperty, productIdent)) deleteProductProperties.append(productProperty) else: productPropertyIdent = u'%s;%s' % (productProperty.productId, productProperty.propertyId) productPropertyIdents.add(productPropertyIdent) if deleteProductProperties: for productProperties in chunk(deleteProductProperties, _CHUNK_SIZE): LOGGER.debug(u"Deleting product properties: {0!r}".format( productProperties)) backend.productProperty_deleteObjects(productProperties) # pylint: disable=maybe-no-member LOGGER.notice(u"Cleaning up product property states") deleteProductPropertyStates = [] for productPropertyState in backend.productPropertyState_getObjects(): # pylint: disable=maybe-no-member productPropertyIdent = u'%s;%s' % (productPropertyState.productId, productPropertyState.propertyId) if productPropertyIdent not in productPropertyIdents: LOGGER.info( u"Marking productPropertyState %s of non existent productProperty '%s' for deletion" % (productPropertyState, productPropertyIdent)) deleteProductPropertyStates.append(productPropertyState) if deleteProductPropertyStates: for productPropertyStates in chunk(deleteProductPropertyStates, _CHUNK_SIZE): LOGGER.debug(u"Deleting product property states: {0!r}".format( productPropertyStates)) backend.productPropertyState_deleteObjects(productPropertyStates) # pylint: disable=maybe-no-member for depot in backend.host_getObjects(type='OpsiDepotserver'): # pylint: disable=maybe-no-member objectIds = set( ClientToDepot['clientId'] for ClientToDepot in backend.configState_getClientToDepotserver( depotIds=depot.id)) objectIds.add(depot.id) productOnDepotIdents = {} for productOnDepot in backend.productOnDepot_getObjects( depotId=depot.id): # pylint: disable=maybe-no-member productIdent = u"%s;%s;%s" % (productOnDepot.productId, productOnDepot.productVersion, productOnDepot.packageVersion) productOnDepotIdents[productOnDepot.productId] = productIdent if not productOnDepotIdents: continue deleteProductPropertyStates = [] updateProductPropertyStates = [] for productPropertyState in backend.productPropertyState_getObjects( # pylint: disable=maybe-no-member objectId=objectIds, productId=productOnDepotIdents.keys(), propertyId=[]): productIdent = productOnDepotIdents.get( productPropertyState.productId) if not productIdent: continue productPropertyIdent = u"%s;%s" % (productIdent, productPropertyState.propertyId) productProperty = productPropertiesToCleanup.get( productPropertyIdent) if not productProperty: continue changed = False newValues = [] removeValues = [] changedValues = [] for value in productPropertyState.values: if value in productProperty.possibleValues: newValues.append(value) continue if productProperty.getType( ) == u'BoolProductProperty' and forceBool( value) in productProperty.possibleValues: newValues.append(forceBool(value)) changedValues.append(value) changed = True continue if productProperty.getType() == u'UnicodeProductProperty': newValue = None for possibleValue in productProperty.possibleValues: if forceUnicodeLower( possibleValue) == forceUnicodeLower(value): newValue = possibleValue break if newValue: newValues.append(newValue) changedValues.append(value) changed = True continue removeValues.append(value) changed = True if changed: if not newValues: LOGGER.info( u"Marking productPropertyState %s for deletion: no value in possible values (%s)" % (productPropertyState, removeValues)) deleteProductPropertyStates.append(productPropertyState) else: productPropertyState.setValues(newValues) LOGGER.info( u"Marking productPropertyState %s for update: values not in possible values: %s, values corrected: %s" % (productPropertyState, removeValues, changedValues)) updateProductPropertyStates.append(productPropertyState) if deleteProductPropertyStates: for productPropertyStates in chunk(deleteProductPropertyStates, _CHUNK_SIZE): LOGGER.debug(u"Deleting product property states: {0!r}".format( productPropertyStates)) backend.productPropertyState_deleteObjects( productPropertyStates) # pylint: disable=maybe-no-member del deleteProductPropertyStates if updateProductPropertyStates: for productPropertyStates in chunk(updateProductPropertyStates, _CHUNK_SIZE): LOGGER.debug(u"Updating product property states: {0!r}".format( productPropertyStates)) backend.productPropertyState_updateObjects( productPropertyStates) # pylint: disable=maybe-no-member del updateProductPropertyStates LOGGER.notice(u"Cleaning up config states") cleanUpConfigStates(backend) LOGGER.notice(u"Cleaning up audit softwares") cleanUpAuditSoftwares(backend) LOGGER.notice(u"Cleaning up audit software on clients") cleanUpAuditSoftwareOnClients(backend)
def connectConfigService(self, allowTemporaryConfigServiceUrls=True): # pylint: disable=too-many-locals,too-many-branches,too-many-statements try: # pylint: disable=too-many-nested-blocks configServiceUrls = config.getConfigServiceUrls( allowTemporaryConfigServiceUrls=allowTemporaryConfigServiceUrls ) if not configServiceUrls: raise Exception("No service url defined") if self._loadBalance and (len(configServiceUrls) > 1): random.shuffle(configServiceUrls) for urlIndex, configServiceURL in enumerate(configServiceUrls): self._configServiceUrl = configServiceURL kwargs = self.connectionThreadOptions() logger.debug("Creating ServiceConnectionThread (url: %s)", self._configServiceUrl) serviceConnectionThread = ServiceConnectionThread( configServiceUrl=self._configServiceUrl, username=config.get('global', 'host_id'), password=config.get('global', 'opsi_host_key'), **kwargs) serviceConnectionThread.daemon = True self.connectionStart(self._configServiceUrl) cancellableAfter = forceInt( config.get('config_service', 'user_cancelable_after')) timeout = forceInt( config.get('config_service', 'connection_timeout')) logger.info( "Starting ServiceConnectionThread, timeout is %d seconds", timeout) serviceConnectionThread.start() for _unused in range(5): if serviceConnectionThread.running: break time.sleep(1) logger.debug("ServiceConnectionThread started") while serviceConnectionThread.running and timeout > 0: if self._should_stop: return logger.debug( "Waiting for ServiceConnectionThread (timeout: %d, alive: %s, cancellable in: %d)", timeout, serviceConnectionThread.is_alive(), cancellableAfter) self.connectionTimeoutChanged(timeout) if cancellableAfter > 0: cancellableAfter -= 1 if cancellableAfter == 0: self.connectionCancelable( serviceConnectionThread.stopConnectionCallback) time.sleep(1) timeout -= 1 if serviceConnectionThread.cancelled: self.connectionCanceled() elif serviceConnectionThread.running: serviceConnectionThread.stop() if urlIndex + 1 < len(configServiceUrls): # Try next url continue self.connectionTimedOut() if not serviceConnectionThread.connected: self.connectionFailed( serviceConnectionThread.connectionError) if serviceConnectionThread.connected and ( serviceConnectionThread.getUsername() != config.get( 'global', 'host_id')): config.set('global', 'host_id', serviceConnectionThread.getUsername().lower()) logger.info("Updated host_id to '%s'", config.get('global', 'host_id')) config.updateConfigFile() if serviceConnectionThread.connected and forceBool( config.get('config_service', 'sync_time_from_service')): logger.info("Syncing local system time from service") try: System.setLocalSystemTime( serviceConnectionThread.configService. getServiceTime(utctime=True)) # pylint: disable=no-member except Exception as err: # pylint: disable=broad-except logger.error("Failed to sync time: '%s'", err) if ("localhost" not in configServiceURL and "127.0.0.1" not in configServiceURL): try: config.set( 'depot_server', 'master_depot_id', serviceConnectionThread.configService.getDepotId( config.get('global', 'host_id')) # pylint: disable=no-member ) config.updateConfigFile() except Exception as err: # pylint: disable=broad-except logger.warning(err) self._configService = serviceConnectionThread.configService self.connectionEstablished() except Exception: self.disconnectConfigService() raise
def getSelection(self, entries, radio=False, width=-1, height=-1, title=_(u'Please select'), text=u'', okLabel=_(u'OK'), cancelLabel=_(u'Cancel')): try: entries = forceList(entries) radio = forceBool(radio) width = forceInt(width) height = forceInt(height) title = forceUnicode(title) text = forceUnicode(text) okLabel = forceUnicode(okLabel) cancelLabel = forceUnicode(cancelLabel) for string in self.confidentialStrings: text = text.replace(string, u'*** confidential ***') if (width <= 0): width = self.getScreen().width - 15 if (height <= 14): height = 13 + len(entries) if text: height += len(text.split(u'\n')) + 1 if (height > self.getScreen().height - 5): height = self.getScreen().height - 5 entriesHeight = len(entries) if (entriesHeight > height - 13): entriesHeight = height - 13 # create text grid textGrid = Grid(1, 1) if text: textHeight = len(text.split(u'\n')) + 1 diff = textHeight + entriesHeight + 13 - height if (diff > 0): entriesHeight -= diff if (entriesHeight < 3): textHeight = textHeight - 3 + entriesHeight entriesHeight = 3 textBox = Textbox(width=width, height=textHeight, text=text.encode(encoding, 'replace'), scroll=1, wrap=1) textGrid.setField(textBox, col=0, row=0) # create widget for entries entriesWidget = None if radio: entriesWidget = Listbox(height=entriesHeight, scroll=1, returnExit=0, width=0, showCursor=0) else: entriesWidget = CheckboxTree(height=entriesHeight, scroll=1) row = 0 numSelected = 0 for i, entry in enumerate(entries): selected = forceBool(entry.get('selected', False)) if radio and (numSelected >= 1): selected = False if selected: numSelected += 1 if radio: entriesWidget.append(text=forceUnicode( entry.get('name', '???')).encode(encoding, 'replace'), item=i) if selected: entriesWidget.setCurrent(i) else: entriesWidget.append(text=forceUnicode( entry.get('name', '???')).encode(encoding, 'replace'), item=i, selected=selected) row += 1 # create grid for buttons buttonsGrid = Grid(2, 1) cancelButton = Button(cancelLabel.encode(encoding, 'replace')) buttonsGrid.setField(cancelButton, col=0, row=0, padding=(0, 0, 10, 0)) okButton = Button(okLabel.encode(encoding, 'replace')) buttonsGrid.setField(okButton, col=1, row=0, padding=(10, 0, 0, 0)) gridForm = GridForm(self._screen, title.encode(encoding, 'replace'), 1, 3) gridForm.add(textGrid, col=0, row=0, padding=(0, 0, 0, 1)) gridForm.add(entriesWidget, col=0, row=1, padding=(0, 0, 0, 1)) gridForm.add(buttonsGrid, col=0, row=2, padding=(0, 0, 0, 0)) # help line helpLine = _( u"<ESC> %s | <F12> %s | <Tab> move cursor | <Space> select" ) % (cancelLabel, okLabel) if text: helpLine += _(u" | <Up/Down> scroll text") self.getScreen().pushHelpLine( forceUnicode(helpLine).encode(encoding, 'replace')) # run gridForm.addHotKey('ESC') gridForm.draw() buttonPressed = None while (buttonPressed not in [okButton, 'F12', cancelButton, 'ESC']): buttonPressed = gridForm.run() self._screen.popWindow() if (buttonPressed not in [okButton, 'F12']): return None result = [] if radio: result.append(entries[entriesWidget.current()]['name']) else: for sel in entriesWidget.getSelection(): result.append(entries[sel]['name']) return result except Exception as e: self.exit() logger.logException(e) raise
def getValue(self, width=-1, height=-1, title=_(u'Please type text'), default=u'', password=False, text=u'', okLabel=_(u'OK'), cancelLabel=_(u'Cancel')): try: width = forceInt(width) height = forceInt(height) title = forceUnicode(title) default = forceUnicode(default) password = forceBool(password) text = forceUnicode(text) okLabel = forceUnicode(okLabel) cancelLabel = forceUnicode(cancelLabel) for string in self.confidentialStrings: text = text.replace(string, u'*** confidential ***') if (width <= 0): width = self.getScreen().width - 15 # create text grid textGrid = Grid(1, 1) if text: textHeight = 0 if (height <= 0): height = self.getScreen().height - 15 textHeight = height - 5 if (textHeight < 2): textHeight = 2 elif (textHeight > len(text.split('\n')) + 1): textHeight = len(text.split('\n')) + 1 else: textHeight = height - len(text.split('\n')) + 1 textBox = Textbox(width=width, height=textHeight, text=text.encode(encoding, 'replace'), scroll=1, wrap=1) textGrid.setField(textBox, col=0, row=0) # create grid for input entryGrid = Grid(1, 1) entry = Entry(width=width, text=default.encode(encoding, 'replace'), hidden=False, password=password, scroll=1, returnExit=0) entryGrid.setField(entry, col=0, row=0, padding=(0, 0, 0, 0)) # create grid for buttons buttonsGrid = Grid(2, 1) cancelButton = Button(cancelLabel.encode(encoding, 'replace')) buttonsGrid.setField(cancelButton, col=0, row=0, padding=(0, 0, 10, 0)) okButton = Button(okLabel.encode(encoding, 'replace')) buttonsGrid.setField(okButton, col=1, row=0, padding=(10, 0, 0, 0)) gridForm = GridForm(self._screen, title.encode(encoding, 'replace'), 1, 3) gridForm.add(textGrid, col=0, row=0, padding=(0, 0, 0, 1)) gridForm.add(entryGrid, col=0, row=1, padding=(0, 0, 0, 1)) gridForm.add(buttonsGrid, col=0, row=2, padding=(0, 0, 0, 0)) gridForm.addHotKey('ESC') # help line helpLine = _( u"<ESC> %s | <F12> %s | <Tab> move cursor | <Space> select" ) % (cancelLabel, okLabel) if text: helpLine += _(u" | <Up/Down> scroll text") self.getScreen().pushHelpLine( forceUnicode(helpLine).encode(encoding, 'replace')) # run gridForm.addHotKey('ESC') gridForm.draw() buttonPressed = None while (buttonPressed not in [okButton, 'F12', cancelButton, 'ESC']): buttonPressed = gridForm.run() self._screen.popWindow() if (buttonPressed not in [okButton, 'F12']): return None return unicode(entry.value(), encoding) except Exception as e: self.exit() logger.logException(e) raise
def getEventConfigs(): # pylint: disable=too-many-locals,too-many-branches,too-many-statements preconditions = {} for (section, options) in config.getDict().items(): section = section.lower() if section.startswith('precondition_'): preconditionId = section.split('_', 1)[1] preconditions[preconditionId] = {} try: for key in options.keys(): if forceBool(options[key]): # Only check if value in precondition is true # false means: do not check state preconditions[preconditionId][key] = True logger.info("Precondition '%s' created: %s", preconditionId, preconditions[preconditionId]) except Exception as err: # pylint: disable=broad-except logger.error("Failed to parse precondition '%s': %s", preconditionId, err) rawEventConfigs = {} for (section, options) in config.getDict().items(): # pylint: disable=too-many-nested-blocks section = section.lower() if section.startswith('event_'): eventConfigId = section.split('_', 1)[1] if not eventConfigId: logger.error("No event config id defined in section '%s'", section) continue rawEventConfigs[eventConfigId] = { 'active': True, 'args': { 'name': eventConfigId.split("{")[0] }, 'super': None, 'precondition': None } try: for key in options.keys(): if key.lower() == 'active': rawEventConfigs[eventConfigId]['active'] = str(options[key]).lower() not in ('0', 'false', 'off', 'no') elif key.lower() == 'super': rawEventConfigs[eventConfigId]['super'] = options[key] if rawEventConfigs[eventConfigId]['super'].startswith('event_'): rawEventConfigs[eventConfigId]['super'] = rawEventConfigs[eventConfigId]['super'].split('_', 1)[1] else: rawEventConfigs[eventConfigId]['args'][key.lower()] = options[key] if '{' in eventConfigId: superEventName, precondition = eventConfigId.split('{', 1) if not rawEventConfigs[eventConfigId]['super']: rawEventConfigs[eventConfigId]['super'] = superEventName.strip() rawEventConfigs[eventConfigId]['precondition'] = precondition.replace('}', '').strip() except Exception as err: # pylint: disable=broad-except logger.error("Failed to parse event config '%s': %s", eventConfigId, err) # Process inheritance newRawEventConfigs = {} while rawEventConfigs: num_configs = len(rawEventConfigs) for eventConfigId in sorted(list(rawEventConfigs)): rawEventConfig = rawEventConfigs[eventConfigId] if rawEventConfig['super']: if rawEventConfig['super'] in newRawEventConfigs: super_args = pycopy.deepcopy(newRawEventConfigs[rawEventConfig['super']]['args']) # Do not overwrite values with emptystring or emptylist (behaves like no value given) cleaned_args = { key : value for key, value in rawEventConfig['args'].items() if not ( key in ("include_product_group_ids", "exclude_product_group_ids") and value in ("", []) ) } super_args.update(cleaned_args) rawEventConfig['args'] = super_args logger.debug("Inheritance for event '%s' processed", eventConfigId) newRawEventConfigs[eventConfigId] = rawEventConfig rawEventConfigs.pop(eventConfigId) elif rawEventConfig['super'] not in rawEventConfigs: logger.error("Super event '%s' not found", rawEventConfig['super']) rawEventConfigs.pop(eventConfigId) else: logger.debug("Inheritance for event '%s' processed", eventConfigId) newRawEventConfigs[eventConfigId] = rawEventConfig rawEventConfigs.pop(eventConfigId) if num_configs == len(rawEventConfigs): logger.error("Failed to process event inheritance: %s", rawEventConfigs) break rawEventConfigs = newRawEventConfigs eventConfigs = {} for (eventConfigId, rawEventConfig) in rawEventConfigs.items(): # pylint: disable=too-many-nested-blocks try: if rawEventConfig['args'].get('type', 'template').lower() == 'template': continue eventConfigs[eventConfigId] = { 'active': rawEventConfig['active'], 'preconditions': {} } if rawEventConfig.get('precondition'): precondition = preconditions.get(rawEventConfig['precondition']) if not precondition: logger.error( "Precondition '%s' referenced by event config '%s' not found, deactivating event", precondition, eventConfigId ) eventConfigs[eventConfigId]['active'] = False else: eventConfigs[eventConfigId]['preconditions'] = precondition for (key, value) in rawEventConfig['args'].items(): try: if key == 'type': eventConfigs[eventConfigId]['type'] = value elif key == 'wql': eventConfigs[eventConfigId]['wql'] = value elif key.startswith(('action_message', 'message')): try: mLanguage = key.split('[')[1].split(']')[0].strip().lower() except Exception: # pylint: disable=broad-except mLanguage = None if mLanguage: if mLanguage == getLanguage(): eventConfigs[eventConfigId]['actionMessage'] = value elif not eventConfigs[eventConfigId].get('actionMessage'): eventConfigs[eventConfigId]['actionMessage'] = value elif key.startswith('shutdown_warning_message'): try: mLanguage = key.split('[')[1].split(']')[0].strip().lower() except Exception: # pylint: disable=broad-except mLanguage = None if mLanguage: if mLanguage == getLanguage(): eventConfigs[eventConfigId]['shutdownWarningMessage'] = value elif not eventConfigs[eventConfigId].get('shutdownWarningMessage'): eventConfigs[eventConfigId]['shutdownWarningMessage'] = value elif key.startswith('name'): try: mLanguage = key.split('[')[1].split(']')[0].strip().lower() except Exception: # pylint: disable=broad-except mLanguage = None if mLanguage: if mLanguage == getLanguage(): eventConfigs[eventConfigId]['name'] = value else: eventConfigs[eventConfigId]['name'] = value elif key == 'start_interval': eventConfigs[eventConfigId]['startInterval'] = int(value) elif key == 'interval': eventConfigs[eventConfigId]['interval'] = int(value) elif key == 'max_repetitions': eventConfigs[eventConfigId]['maxRepetitions'] = int(value) elif key == 'activation_delay': eventConfigs[eventConfigId]['activationDelay'] = int(value) elif key == 'notification_delay': eventConfigs[eventConfigId]['notificationDelay'] = int(value) elif key == 'action_warning_time': eventConfigs[eventConfigId]['actionWarningTime'] = int(value) elif key == 'action_user_cancelable': eventConfigs[eventConfigId]['actionUserCancelable'] = int(value) elif key == 'shutdown': eventConfigs[eventConfigId]['shutdown'] = forceBool(value) elif key == 'reboot': eventConfigs[eventConfigId]['reboot'] = forceBool(value) elif key == 'shutdown_warning_time': eventConfigs[eventConfigId]['shutdownWarningTime'] = int(value) elif key == 'shutdown_warning_repetition_time': eventConfigs[eventConfigId]['shutdownWarningRepetitionTime'] = int(value) elif key == 'shutdown_user_cancelable': eventConfigs[eventConfigId]['shutdownUserCancelable'] = int(value) elif key == 'shutdown_user_selectable_time': eventConfigs[eventConfigId]['shutdownUserSelectableTime'] = forceBool(value) elif key == 'shutdown_warning_time_after_time_select': eventConfigs[eventConfigId]['shutdownWarningTimeAfterTimeSelect'] = int(value) elif key == 'block_login': eventConfigs[eventConfigId]['blockLogin'] = forceBool(value) elif key == 'lock_workstation': eventConfigs[eventConfigId]['lockWorkstation'] = forceBool(value) elif key == 'logoff_current_user': eventConfigs[eventConfigId]['logoffCurrentUser'] = forceBool(value) elif key == 'process_shutdown_requests': eventConfigs[eventConfigId]['processShutdownRequests'] = forceBool(value) elif key == 'get_config_from_service': eventConfigs[eventConfigId]['getConfigFromService'] = forceBool(value) elif key == 'update_config_file': eventConfigs[eventConfigId]['updateConfigFile'] = forceBool(value) elif key == 'write_log_to_service': eventConfigs[eventConfigId]['writeLogToService'] = forceBool(value) elif key == 'cache_products': eventConfigs[eventConfigId]['cacheProducts'] = forceBool(value) elif key == 'cache_max_bandwidth': eventConfigs[eventConfigId]['cacheMaxBandwidth'] = int(value) elif key == 'cache_dynamic_bandwidth': eventConfigs[eventConfigId]['cacheDynamicBandwidth'] = forceBool(value) elif key == 'use_cached_products': eventConfigs[eventConfigId]['useCachedProducts'] = forceBool(value) elif key == 'sync_config_from_server': eventConfigs[eventConfigId]['syncConfigFromServer'] = forceBool(value) elif key == 'sync_config_to_server': eventConfigs[eventConfigId]['syncConfigToServer'] = forceBool(value) elif key == 'use_cached_config': eventConfigs[eventConfigId]['useCachedConfig'] = forceBool(value) elif key == 'update_action_processor': eventConfigs[eventConfigId]['updateActionProcessor'] = forceBool(value) elif key == 'action_type': eventConfigs[eventConfigId]['actionType'] = forceUnicodeLower(value) elif key == 'event_notifier_command': eventConfigs[eventConfigId]['eventNotifierCommand'] = config.replace(forceUnicodeLower(value), escaped=True) elif key == 'event_notifier_desktop': eventConfigs[eventConfigId]['eventNotifierDesktop'] = forceUnicodeLower(value) elif key == 'process_actions': eventConfigs[eventConfigId]['processActions'] = forceBool(value) elif key == 'action_notifier_command': eventConfigs[eventConfigId]['actionNotifierCommand'] = config.replace(forceUnicodeLower(value), escaped=True) elif key == 'action_notifier_desktop': eventConfigs[eventConfigId]['actionNotifierDesktop'] = forceUnicodeLower(value) elif key == 'action_processor_command': eventConfigs[eventConfigId]['actionProcessorCommand'] = forceUnicodeLower(value) elif key == 'action_processor_desktop': eventConfigs[eventConfigId]['actionProcessorDesktop'] = forceUnicodeLower(value) elif key == 'action_processor_timeout': eventConfigs[eventConfigId]['actionProcessorTimeout'] = int(value) elif key == 'trusted_installer_detection': eventConfigs[eventConfigId]['trustedInstallerDetection'] = forceBool(value) elif key == 'shutdown_notifier_command': eventConfigs[eventConfigId]['shutdownNotifierCommand'] = config.replace(forceUnicodeLower(value), escaped=True) elif key == 'shutdown_notifier_desktop': eventConfigs[eventConfigId]['shutdownNotifierDesktop'] = forceUnicodeLower(value) elif key == 'pre_action_processor_command': eventConfigs[eventConfigId]['preActionProcessorCommand'] = config.replace(forceUnicodeLower(value), escaped=True) elif key == 'post_action_processor_command': eventConfigs[eventConfigId]['postActionProcessorCommand'] = config.replace(forceUnicodeLower(value), escaped=True) elif key == 'post_event_command': eventConfigs[eventConfigId]['postEventCommand'] = config.replace(forceUnicodeLower(value), escaped=True) elif key == 'action_processor_productids': if not isinstance(value, list): value = [x.strip() for x in value.split(",") if x.strip()] eventConfigs[eventConfigId]['actionProcessorProductIds'] = forceList(value) elif key == 'depot_protocol': eventConfigs[eventConfigId]['depotProtocol'] = forceUnicodeLower(value) elif key == 'exclude_product_group_ids': if not isinstance(value, list): value = [x.strip() for x in value.split(",") if x.strip()] eventConfigs[eventConfigId]['excludeProductGroupIds'] = forceList(value) elif key == 'include_product_group_ids': if not isinstance(value, list): value = [x.strip() for x in value.split(",") if x.strip()] eventConfigs[eventConfigId]['includeProductGroupIds'] = forceList(value) elif key == 'working_window': eventConfigs[eventConfigId]['workingWindow'] = str(value) else: logger.error("Skipping unknown option '%s' in definition of event '%s'", key, eventConfigId) for section in list(config.getDict()): if section.startswith("event_") and config.has_option(section, key): logger.info("Removing config option %s.%s", section, key) config.del_option(section, key) except Exception as err: # pylint: disable=broad-except logger.debug(err, exc_info=True) logger.error("Failed to set event config argument '%s' to '%s': %s", key, value, err) logger.info( "Event config '%s' args:\n%s", eventConfigId, pprint.pformat(eventConfigs[eventConfigId], indent=4, width=300, compact=False) ) except Exception as err: # pylint: disable=broad-except logger.error(err, exc_info=True) return eventConfigs
def testForceBoolWithFalsyValues(value): assert forceBool(value) is False