def _discoverAscsInPf(doc, system, system_osh, oshPerInstance): enque_host, enque_instance_nr = AscsInfoPfParser.parse(doc) #Change implemented within the scope of issue "QCIM1H96235 Job ABAP Topology discovers Central Services related to wrong SAP System" #In case an application server is being reinstalled and / or switched to a new SAP System we can not trust data in UCMDB as for SAP SYSTEM NAME #And must check if this data in trigger coincides to the one on profile, in case it's not true - STOP the discovery with ERROR and REPORT NOTHING. #Valid data will be reported from a new trigger with new valid SAP SYSTEM NAME system_name = doc.get('SAPSYSTEMNAME') if system_name and system and system_name.upper().strip() != system.getName().upper().strip(): logger.error('Trigger data and destination SAP System name are not equal. Stopping discovery.') raise SapSystemInconsistentDataException('SAP System name is miss-matched in trigger and destination') if enque_host: logger.info("Found ASCS: %s %s" % (enque_host, enque_instance_nr)) instance = sap.Instance('ASCS', enque_instance_nr, enque_host) # create ASCS instance with membership ascs_osh, vector = _report_ascs_osh(enque_host, enque_instance_nr, system) if ascs_osh: vector.add(sap.LinkReporter().reportMembership(system_osh, ascs_osh)) for _, inst_osh in oshPerInstance.iteritems(): vector.add(sap.LinkReporter().reportMembership(system_osh, inst_osh)) return vector else: return None else: return None
def parseSapSystemFromInstanceBasePath(path, parseHostname=False): r''' Parse instance base path and decompose it onto system and instance object representation. Format of substring participated in search is /<SAPSYSTEMNAME>/<INSTANCE_NAME>/<SAPLOCALHOST> @types: str, bool -> sap.System @param parseHostname: Influence on <SAPLOCALHOST> part parsing. When parameter set to True will attempt to parse hostname. Parameter has to be used carefully and only in places where there is confidence in right pattern format. @raise ValueError: Unsupported path format''' if not path: raise ValueError("Path is not specified") mo = re.search( r'''[/\\]([a-z]{3})[/\\] # SAPSYSTEMNAME ([a-z]+)(\d\d) # INSTANCE_NAME (?:[/\\]([^/\\]+))?\s* # SAPLOCALHOST ''', path, re.I | re.VERBOSE) if not mo: raise ValueError("Unsupported path format") sid = mo.group(1) number = mo.group(3) name = mo.group(2) + number hostname = None if parseHostname and len(mo.groups()) > 3: hostname = mo.group(4).strip() return sap.System(sid).addInstance(sap.Instance(name, number, hostname))
def parseInstanceFromName(instanceName): r'@types: str -> sap.Instance' assert instanceName matchObj = re.match(r'\s*([a-z]+?)(\d+)', instanceName, re.I) if matchObj: return sap.Instance(matchObj.group(1), matchObj.group(2)) raise ValueError("Wrong instance name")
def parse_inst_in_pf(doc): ''' Parse instance related information from profile @types: IniDocument -> sap.Instance ''' inst = parseInstanceFromName(doc.get('INSTANCE_NAME')) hostname = doc.get('SAPLOCALHOST') fqdn = doc.get('SAPLOCALHOSTFULL') if not hostname and fqdn and not _has_substitution_variable(fqdn): hostname = parse_hostname_from_fqdn(fqdn) return sap.Instance(inst.name, inst.number, hostname)
def _parseInstFullInformation(self, props): r'@types: java.util.Properties -> sap.Instance' name = props.get('InstanceName') vmParameters = props.get('VmParameters') or () inst = self._parseInst(name, vmParameters) if not inst: raise ValueError("Failed to parse instance information") myName = _findJavaSysParameter(vmParameters, 'SAPMYNAME') hostname = None if myName: _, hostname, _ = sap_discoverer.parseSystemAndInstanceDetails(myName) return sap.Instance(inst.getName(), inst.getNumber(), hostname)
def __parse(self, items): r'@types: ? -> list[InstanceInfo]' servers = [] for i in xrange(items.getRowCount()): name = items.getCell(i, 0) logger.debug('server name: %s' % items.getCell(i, 0)) logger.debug('server hostname: %s' % items.getCell(i, 1)) logger.debug('server ip: %s' % items.getCell(i, 4)) try: logger.debug("Process server: %s" % name) hostname, sid, number = self._decomposeServerName(name) # get instance name from start profile path startPfPath = items.getCell(i, 9) instancePfPath = items.getCell(i, 10) instance = self._extractInstanceInfoFromProfilePath( sid, startPfPath or instancePfPath) instance = sap.Instance(instance.name, number, hostname, startPfPath=startPfPath, instancePfPath=instancePfPath) sapSystem = sap.System(sid) # host-info ip = sap.createIp(items.getCell(i, 4)) hostname = items.getCell(i, 1) or hostname address = sap.Address(hostname, (ip, )) host = self.Host(address, osInfo=items.getCell(i, 2), machineType=items.getCell(i, 3)) # server-info startDate = self._parseStartDate(items.getCell(i, 5)) versionInfo = sap.VersionInfo(items.getCell(i, 6), patchLevel=items.getCell(i, 8)) instanceInfo = self.createInstanceInfo( instance, sapSystem, host, homeDirPath=items.getCell(i, 11), dbLibraryInfo=items.getCell(i, 7), codePage=items.getCell(i, 12), numberOfProcesses=items.getCell(i, 13), versionInfo=versionInfo, startDate=startDate) servers.append(instanceInfo) except Exception, e: logger.warnException("%s. %s" % (name, str(e)))
def _extractInstanceInfoFromProfilePath(self, sid, path): r''' Profile file name contains information about instance name and its number in format '<something>_<instance-name>_<something>' @types: str -> sap.Instance''' if not (path and sid): raise ValueError("Path or SID is not specified") matchObj = re.match(r'.*?(?:START|%s)_(.+?)(\d+)_(\w+)' % sid, path, re.I) if matchObj: return sap.Instance(matchObj.group(1), matchObj.group(2), hostname=matchObj.group(3)) raise ValueError("Failed to parse instance from profile name")
def _parseScsInstance(self, document): r'''@types: IniDocument -> tuple[sap.Instance, Endpoint or None] @return: tuple of SCS instance itself and message server endpoint ''' instance = None msEndpoint = None hostname = document.get('j2ee/scs/host') number = document.get('j2ee/scs/system') msPort = document.get('j2ee/ms/port') if hostname and number: instance = sap.Instance('SCS', number, hostname) if msPort: msEndpoint = netutils.createTcpEndpoint(hostname, msPort) return instance, msEndpoint
def reportScsBasedOnMsgPort(system, hostname, msgEndpoints, systemOsh, clusterOsh, enqEndpoints=(), reportName=False): r''' @param reportName: influence on `name` attribute reporting. In some cases composite name attribute may contain not correct host information that has impact on reconciliation. Better do not report data we are not sure @types: sap.System, str, list[Endpoint], osh, list[Endpoint], bool -> oshv ''' vector = ObjectStateHolderVector() if not msgEndpoints: logger.warn("Failed to discover SCS - no message server information") return vector ips = (map(netutils.Endpoint.getAddress, msgEndpoints) + map(netutils.Endpoint.getAddress, enqEndpoints)) hostReporter = sap.HostReporter(sap.HostBuilder()) hostOsh, hVector = hostReporter.reportHostWithIps(*ips) vector.addAll(hVector) systemOsh.setStringAttribute('data_note', 'This SAP System link to ' + hostOsh.getAttributeValue('host_key')) vector.add(systemOsh) instIp = sap.createIp(first(ips)) msgEndpoint = first(msgEndpoints) number = sap_discoverer.parseInstNrInMsgServerPort(msgEndpoint.getPort()) inst = sap.Instance('SCS', number, hostname=hostname) pdo = sap_jee.InstanceBuilder.InstancePdo(inst, system, ipAddress=instIp) scsBuilder = sap_jee.ScsInstanceBuilder(reportName=reportName) instReporter = sap_jee.InstanceReporter(scsBuilder) instOsh = instReporter.reportInstancePdo(pdo, hostOsh) vector.add(instOsh) linkReporter = sap.LinkReporter() vector.add(linkReporter.reportMembership(clusterOsh, instOsh)) vector.add(linkReporter.reportMembership(systemOsh, instOsh)) for endpoint in (msgEndpoints + enqEndpoints): _, eVector = sap._reportEndpointLinkedToSoftware(endpoint, hostOsh, instOsh) vector.addAll(eVector) return vector
def _parseInstanceInfo(self, item): r'@types: Properties -> InstanceInfo' hostname = item.get('Host') if not hostname: raise ValueError("Address is not specified") ports = keep(item.get, self.ENDPOINT_NAMES) endpoints = [netutils.createTcpEndpoint(hostname, p) for p in ports] state = self._parseInstanceState(item.get('State')) instName = item.get('Caption') fullName = item.get('Name') _inst = sap_discoverer.parseInstanceFromName(instName) instName = _inst.name if fullName: details = sap_discoverer.parseSystemAndInstanceDetails(fullName) _, hostname, nr = details else: nr = _inst.number instanceWithHostname = sap.Instance(instName, nr, hostname=hostname) return self.InstanceInfo(instanceWithHostname, endpoints, state=state)
def parseSapSystemFromInstanceProfileName(profileName): r''' Format of profile name is: <SAPSYSTEMNAME>_<INSTANCE_NAME>_<SAPLOCALHOST> @types: str -> sap.System @raise ValueError: Wrong instance profile name @note: potentially relevant only to ABAP instance PF naming ''' if not profileName: raise ValueError("Profile name is not specified") tokens = profileName.split('_', 2) if len(tokens) != 3: raise ValueError("Wrong instance profile name") systemName = tokens[0] instanceName = tokens[1] hostname = tokens[2] sapSystem = sap.System(systemName) instance = parseInstanceFromName(instanceName) sapSystem.addInstance( sap.Instance(instance.getName(), instance.getNumber(), hostname)) return sapSystem
def _reportServer(server, parsedName, ips, system, systemOsh): ''' @types: GetServers.Server, tuple, list[ip_addr._BaseIP], System, osh -> oshv ''' vector = ObjectStateHolderVector() isScs, hostname, _, nr, _ = parsedName hostReporter = sap.HostReporter(sap.HostBuilder()) hostOsh, hVector = hostReporter.reportHostWithIps(*ips) # 1) name of instance will be ignore during reporting # 2) hostname used from name not from `hostname` field of server # as usually name contains alias that is interesting in different # business cases inst = sap.Instance('fake', nr, hostname) serverType = GetServers.getServerTypeByRole(server.role) reportFn = (serverType == sap.SystemType.JAVA and _reportJavaServer or _reportAbapServer) vector.addAll(hVector) vector.addAll(reportFn(inst, system, isScs, hostOsh, systemOsh)) return vector
def process(self, context): r''' @types: applications.ApplicationSignatureContext ''' # ==================== DISCOVERY shell = context.client fs = file_system.createFileSystem(shell) pathtools = file_system.getPath(fs) # 1) get process related application application = context.application connectionIp = application.getConnectionIp() # 2) find out process where path to the instance profile is stored logger.info(" Get executable path of main process ") mainProcess = application.getMainProcesses()[0] # 3) logger.info("Found out path to instance profile") instanceProfilePath = self.__getProfilePath(mainProcess) # 4) logger.info("Instance profile path: ", instanceProfilePath, ". Get content") getContent = fptools.safeFunc(self.__getContent, Exception) profileFile = (instanceProfilePath and getContent(shell, pathtools, instanceProfilePath)) if not profileFile: logger.warn("Failed to get content of instance profile") return # 5) parse content using instance and default profile parsers logger.info("Make configuration parsing") iniParser = sap_discoverer.IniParser() instancePfParser = sap_discoverer.InstanceProfileParser(iniParser) try: instanceProfile = instancePfParser.parseContent( profileFile.content) except Exception: logger.warnException("Failed to parse instance profile") else: traceConfig = None runtimeConfig = None sapInstance = instanceProfile.instance sapInstance = sap.Instance(sapInstance.name + sapInstance.number, sapInstance.number, sapInstance.hostname) # 6) Process runtime.properties that contains information about # Solution Manager and SLD if present logger.info("Create agent layout") logger.info("Get content of runtime properties") agentLayout = fptools.safeFunc( sap_smd_discoverer.createAgentLayoutFromBinPath)( (pathtools.isAbsolute(mainProcess.executablePath) and mainProcess.executablePath or discoverExecutablePath(shell, mainProcess)), fs, pathtools) if agentLayout: propertiesFile = getContent( shell, pathtools, agentLayout.getRuntimePropertiesPath()) if propertiesFile: parser = sap_smd_discoverer.RuntimePropertiesParser( sap_discoverer.IniParser()) try: runtimeConfig = parser.parse(propertiesFile.content) except Exception: logger.warnException( "Failed to parse runtime properties") logger.info("Find out version information") devSmdAgentFile = getContent( shell, pathtools, agentLayout.getDevSmdAgentConfigFile()) if devSmdAgentFile: configParser = sap_smd_discoverer.DevSmdAgentConfigParser() # find config with corresponding PID (of main process) hasMainProcessPid = lambda c, pid=mainProcess.getPid( ): c.pid == pid traceConfig = fptools.findFirst( hasMainProcessPid, configParser.parse(devSmdAgentFile.content)) if not traceConfig: logger.warn( "Failed to find trace information for the main process" ) # === REPORT === smdAgentOsh = application.getOsh() vector = context.resultsVector endpointReporter = netutils.EndpointReporter( netutils.ServiceEndpointBuilder()) configFileReporter = file_topology.Reporter( file_topology.Builder()) linkReporter = sap.LinkReporter() smdAgentBuilder = sap_smd.Builder() softwareBuilder = sap.SoftwareBuilder() softwareReporter = sap.SoftwareReporter(sap.SoftwareBuilder()) resolverByShell = netutils.DnsResolverByShell(shell) processOsh = mainProcess.getOsh() # x) update name of application using instance name softwareBuilder.updateName(smdAgentOsh, sapInstance.getName()) # x) configuration files related to running_software vector.add(configFileReporter.report(profileFile, smdAgentOsh)) if traceConfig: # x) update version information in application smdAgentOsh = softwareBuilder.updateVersionInfo( smdAgentOsh, traceConfig.versionInfo) if traceConfig.jstartVersionInfo: smdAgentOsh = smdAgentBuilder.updateJstartVersionInfo( smdAgentOsh, traceConfig.jstartVersionInfo) # x) show relation between agent and # - SMD server / no enough information / # - message server of SCS OR Solution Manager, represented as agent connection endpoint # - SLD if propertiesFile and runtimeConfig: # x) report properties file as configuration document vector.add( configFileReporter.report(propertiesFile, smdAgentOsh)) # x) Report relation between agent and SLD server and SolMan # Resolve endpoint addresses # make function that will accept endpoint only resolveEndpointFn = fptools.partiallyApply( self.__resolveEndpointAddress, fptools.safeFunc(resolverByShell.resolveIpsByHostname, []), fptools._) # - SLD relation if runtimeConfig.sldEndpoint: for endpoint in resolveEndpointFn( runtimeConfig.sldEndpoint): sldHostOsh = endpointReporter.reportHostFromEndpoint( endpoint) vector.add(sldHostOsh) sldEndpointOsh = endpointReporter.reportEndpoint( endpoint, sldHostOsh) vector.add(sldEndpointOsh) # this unknown server type must be SLD server sldOsh = softwareReporter.reportUknownSoftware( sldHostOsh) vector.add(sldOsh) vector.add( linkReporter.reportUsage(sldOsh, sldEndpointOsh)) # report link between process and SLD server endpoint vector.add( linkReporter.reportClientServerRelation( processOsh, sldEndpointOsh)) # - Solution Manager relation agentConnectionEndpoint = runtimeConfig.getAgentConnecitonEndpoint( ) if agentConnectionEndpoint: for endpoint in resolveEndpointFn(agentConnectionEndpoint): hostOsh = endpointReporter.reportHostFromEndpoint( endpoint) vector.add(hostOsh) endpointOsh = endpointReporter.reportEndpoint( endpoint, hostOsh) vector.add(endpointOsh) softwareOsh = softwareReporter.reportUknownSoftware( hostOsh) vector.add(softwareOsh) vector.add( linkReporter.reportUsage(softwareOsh, endpointOsh)) # report link between process and SolMan end-point vector.add( linkReporter.reportClientServerRelation( processOsh, endpointOsh))
return None # TODO replace this by reportInstances function def _report_ascs_osh(host_name, instance_number, system): resolver = dns_resolver.SocketDnsResolver() ips = [] try: ips = resolver.resolve_ips(host_name) except netutils.ResolveException, re: logger.warn("Failed to resolve %s" % host_name) if ips: hostReporter = sap.HostReporter(sap.HostBuilder()) host_osh, vector = hostReporter.reportHostWithIps(*ips) instance = sap.Instance('ASCS', instance_number, host_name) ascs_pdo = sap_abap.AscsInstanceBuilder.createPdo(instance, system) ascs_builder = sap_abap.AscsInstanceBuilder() reporter = sap_abap.InstanceReporter(ascs_builder) ascs_osh = reporter.reportInstance(ascs_pdo, host_osh) vector.add(ascs_osh) vector.add(host_osh) return ascs_osh, vector return None, None def _updateSystemOsh(system, systemOsh): '@types: System, osh -> osh'
def _createAnonymousInstFromFullName(name): r'@types: str -> sap.Instance' _, hostname, nr = sap_discoverer.parseSystemAndInstanceDetails(name) return sap.Instance('x', nr, hostname)