def getNamedPipes(runtime, client, hostname, instanceName, regInstancePath, dbContextId): """Find out whether Named Pipes are enabled.""" path = r'{}\MSSQLServer\SuperSocketNetLib\Np'.format(regInstancePath) command = 'Get-ItemProperty -Path "' + path + '" | %{$_.DisplayName,$_.Enabled,$_.PipeName -Join ":==:"}' (stdOut, stdError, hitProblem) = client.run(command, 5) ## Sample output: ## =================================== ## Named Pipes:==:0:==:\\.\pipe\sql\query ## =================================== if len(stdOut) > 0: (protocol, enabled, pipeName) = stdOut.split(':==:') if enabled != '0': attributes = {} attributes['name'] = instanceName attributes['protocol'] = protocol attributes['logical_context'] = pipeName attributes['db_type'] = 'SqlServer' attributes['source'] = 'Local' attributes['hostname'] = hostname ## Create Named Pipes connection parameter and link to dbContext connectionParameterId, exists = addObject(runtime, 'DBConnectionParameter', **attributes) addLink(runtime, 'Enclosed', dbContextId, connectionParameterId) ## Debugging aid runtime.logger.report(' {} enabled on instance {}:'.format( protocol, instanceName)) ## end getNamedPipes return
def createObjects(runtime, realmUtil, trackedZones, trackedIPs, recordData, domainName, ownerName, trackEveryIpInDNS, trackEveryIpInDB, trackIPsInRealm, ipAddrToIdDict): """Conditionally create IPs and link in the records.""" recordId = None ipId = None ## If we are told to create all DNS content, do not check values if not trackEveryIpInDNS: ## Otherwise, we have two more conditions to check... ## if told to create DNS for all IPs already resident in the DB if trackEveryIpInDB: if recordData in ipAddrToIdDict: ipId = ipAddrToIdDict[recordData] runtime.logger.report(' trackedByDB using id: {ipId!r}', ipId=ipId) addObject(runtime, 'IpAddress', uniqueId=ipId) elif trackIPsInRealm: if not realmUtil.isIpInRealm(recordData): runtime.logger.report( ' ... skipping IP {recordData!r} because it is neither in the DB nor in the realm configuration', recordData=recordData) return recordId else: runtime.logger.report( ' ... skipping IP {recordData!r} because it is not in the DB', recordData=recordData) return recordId elif trackIPsInRealm: if not realmUtil.isIpInRealm(recordData): runtime.logger.report( ' ... skipping IP {recordData!r} because it is not in the realm configuration', recordData=recordData) return recordId ## Create the IP first (if not using a handle from the DB) if ipId is None: try: ipId = createNewIp(runtime, trackedIPs, recordData) except ValueError: runtime.logger.report('ValueError in getThisIp: {valueError!r}', valueError=str(sys.exc_info()[1])) return recordId ## Create the zone if necessary if domainName not in trackedZones.keys(): ## Add the zone onto (or back onto) the result set zoneId, exists = addObject(runtime, 'Domain', name=domainName) trackedZones[domainName] = zoneId zoneId = trackedZones[domainName] ## Create the DNS record recordId, exists = addObject(runtime, 'NameRecord', name=ownerName, value=recordData) addLink(runtime, 'Enclosed', zoneId, recordId) addLink(runtime, 'Usage', ipId, recordId) ## end createObjects return recordId
def createObject(runtime, nodeId, properties): """Create the file object and link it to the node. Arguments: runtime (dict) : used for providing input into jobs and tracking the job thread through the life of its runtime nodeId (string) : 'object_id' of the Node that our client is connected to; not used here... just stubbed for common practice properties (dict) : dictionary with key:value pairs from command output """ try: attributes = {} setAttribute(properties, 'Name', attributes, 'name') setAttribute(properties, 'FullName', attributes, 'path') setAttribute(properties, 'Extension', attributes, 'extension') ## In production scenario, convert string dates to datetime type before setAttribute(properties, 'CreationTime', attributes, 'file_created') setAttribute(properties, 'LastWriteTime', attributes, 'file_modified') setAttribute(properties, 'Hash', attributes, 'md5hash') ## Create the file fileId, exists = addObject(runtime, 'FileCustom', **attributes) ## Link it to the node addLink(runtime, 'Enclosed', nodeId, fileId) except: stacktrace = traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]) runtime.logger.error(' Failure in createObject: {stacktrace!r}', stacktrace=stacktrace) ## end createObject return
def trackWebResponse(runtime, ipAddress, ipObjectId, port, url, responseCode, responseText, title): """Create the IP, Port, and WebEnabledEndpoint.""" ## Recreate the IP by the identifier addObject(runtime, 'IpAddress', uniqueId=ipObjectId) ## Create TcpIpPort tcpIpPortId, portExists = addObject(runtime, 'TcpIpPort', name=str(port), port=int(port), ip=ipAddress, port_type='tcp', is_tcp=True) ## Don't need to HTML encode all, but definitely double quotes for JSON ## result object; and truncate in case the response was too large responseText = responseText.replace('"', '"')[:4096] ## Create WebEnabledEndpoint webId, certExists = addObject(runtime, 'WebEnabledEndpoint', url=url, ip=ipAddress, port=port, title=title, response_code=responseCode, response_text=responseText) ## Links addLink(runtime, 'Enclosed', ipObjectId, tcpIpPortId) addLink(runtime, 'Enclosed', tcpIpPortId, webId) ## end trackWebResponse return
def qualifyInstance(runtime, client, instanceName, instanceData, regInstancePath, nodeId): """Request details from each existing database instance.""" dbContextId = None try: instanceId = instanceData.get('id') ## C:\Program Files\Microsoft SQL Server\MSSQL11.TEST\Setup setupPath = '{}\Setup'.format(regInstancePath) command = 'Get-ItemProperty -Path "' + setupPath + '" | %{$_.Version,$_.PatchLevel,$_.Edition,$_.EditionType,$_.SqlProgramDir,$_.SQLPath -Join ":==:"}' (stdOut, stdError, hitProblem) = client.run(command, 10) ## Sample output: ## =================================== ## 10.50.1600.1:==:10.50.1617.0:==:Express Edition:==:Express Edition with Advanced Services:==:c:\Program Files\Microsoft SQL Server\:==:c:\Program Files\Microsoft SQL Server\MSSQL10.SQLEXPRESS\MSSQL ## 11.0.2100.60:==:11.0.2100.60:==:Express Edition:==:Express Edition:==:C:\Program Files\Microsoft SQL Server\:==:C:\Program Files\Microsoft SQL Server\MSSQL11.SQLEXPTRACK201\MSSQL ## 13.2.5026.0:==:13.2.5026.0:==:Developer Edition:==:Developer Edition:==:C:\Program Files\Microsoft SQL Server\:==:C:\Program Files\Microsoft SQL Server\MSSQL13.MSSQLSERVER\MSSQL ## =================================== if hitProblem: raise EnvironmentError( 'Problem gathering details on instance {}'.format(instanceId)) if (stdOut is None or len(stdOut) <= 0): runtime.logger.report( 'No details found on instance {}'.format(instanceId)) if stdError is not None: runtime.logger.report(' Error: {stdError!r}', stdError=stdError) else: (version, patchLevel, edition, editionType, sqlProgramDir, sqlPath) = stdOut.split(':==:') ## Create the attributes to send to addObject attr = {} attr['name'] = instanceName attr['path'] = sqlPath attr['version'] = version attr['patch_level'] = patchLevel attr['edition'] = edition attr['edition_type'] = editionType attr['program_dir'] = sqlProgramDir ## Create the DB context object and link to the Node dbContextId, exists = addObject(runtime, 'SqlServerContext', **attr) addLink(runtime, 'Enclosed', nodeId, dbContextId) ## Debugging aid runtime.logger.report( 'Setup info on instance {}:'.format(instanceName)) runtime.logger.report(' version: {}'.format(version)) runtime.logger.report(' patchLevel: {}'.format(patchLevel)) runtime.logger.report(' edition: {}'.format(edition)) runtime.logger.report(' editionType: {}'.format(editionType)) runtime.logger.report(' sqlProgramDir: {}'.format(sqlProgramDir)) runtime.logger.report(' sqlPath: {}'.format(sqlPath)) except: runtime.setError(__name__) ## end qualifyInstance return dbContextId
def newLink(text): try: link = text.split(" ")[0] cat = text.split(" ")[1] utils.addLink(link, cat) return "The link '" + link + "' [" + cat + "] has been reported as useful." except: return None
def createObject(runtime, nodeId, properties): attributes = {} setAttribute(properties, 'Name', attributes, 'name') setAttribute(properties, 'FullName', attributes, 'path') setAttribute(properties, 'Extension', attributes, 'extension') setAttribute(properties, 'CreationTime', attributes, 'file_created') setAttribute(properties, 'LastWriteTime', attributes, 'file_modified') setAttribute(properties, 'Hash', attributes, 'md5hash') ## Create files and link to the node fileId = addObject(runtime, 'FileCustom', **attributes) addLink(runtime, 'Enclosed', nodeId, fileId)
def getTcpIp(runtime, client, hostname, instanceName, regInstancePath, dbContextId): """Find out whether TCP/IP is enabled.""" tcpPath = r'{}\MSSQLServer\SuperSocketNetLib\TCP'.format(regInstancePath) command = 'Get-ItemProperty -Path "' + tcpPath + '" | %{$_.DisplayName,$_.Enabled,$_.ListenOnAllIPs,$_.KeepAlive -Join ":==:"}' (stdOut, stdError, hitProblem) = client.run(command, 5) ## Sample output: ## =================================== ## TCP/IP:==:1:==:1:==:30000 ## =================================== if len(stdOut) > 0: (protocol, enabled, listenOnAllIPs, keepAlive) = stdOut.split(':==:') if enabled == '0': return runtime.logger.report(' {} enabled on instance {}:'.format( protocol, instanceName)) runtime.logger.report(' enabled: {}'.format(enabled)) runtime.logger.report(' listenOnAllIPs: {}'.format(listenOnAllIPs)) runtime.logger.report(' keepAlive: {}'.format(keepAlive)) ## Get all TCP/IP settings command = 'Get-ChildItem -Path "' + tcpPath + '" | foreach { $_.PSChildName }' (stdOut, stdError, hitProblem) = client.run(command, 5) ## Sample output: ## =================================== ## IP1 ## IP2 ## ... ## IPAll ## =================================== tcpIpEntries = [] for entry in stdOut.splitlines(): if entry.strip().lower() == 'ipall': (tcpPortAll, tcpDynamicPortAll) = getIpAllEntry(runtime, client, instanceName, protocol, tcpPath, entry.strip().lower()) else: getTcpIpEntry(runtime, client, instanceName, protocol, hostname, tcpPath, entry.strip().lower(), tcpIpEntries) for entry in tcpIpEntries: normalizePort(entry, tcpPortAll, tcpDynamicPortAll) if entry['port'] > 0: ## Create TCP/IP connection parameter and link to dbContext connectionParameterId, exists = addObject( runtime, 'DBConnectionParameter', **entry) addLink(runtime, 'Enclosed', dbContextId, connectionParameterId) ## end getTcpIp return
def createObjects(runtime, client, realm): """Create and connect the node and REST object.""" ## Get necessary info from the client (endpoint, reference, port, url) = client.restDetails() ## Create the node nodeId, exists = addObject(runtime, 'Node', hostname=endpoint, partial=True) ## Create a REST object to leverage for future connections restId, exists = addObject(runtime, 'REST', container=nodeId, ipaddress=endpoint, protocol_reference=reference, realm=realm, port=port, base_url=url, node_type='OCP') ipId, exists = addIp(runtime, address=endpoint) ## And connect the objects addLink(runtime, 'Enclosed', nodeId, restId) addLink(runtime, 'Usage', nodeId, ipId)
def startNormalization(runtime, queryResult, flatenedResult, transformFile, transformName): """Perform data normalization on a result, according to the tranformation file.""" ## Don't use dictionary.get(); I want to stop if class/attrs are missing classToCreate = transformFile['classToCreate'] mappedAttributes = {} containerClass = None containerId = None attributes = transformFile['attributes'] for name,data in attributes.items(): mappingRule = data.get('mappingRule') if name == 'container': containerClass = data.get('class') containerId = getAttribute(flatenedResult, mappingRule, 'string') if (containerClass is None or containerId is None): runtime.logger.report('Improper mapped container values.') return else: isRequired = data.get('isRequired', False) dataType = getDataType(runtime, data, transformName, transformFile) mappedValue = getAttribute(flatenedResult, mappingRule, dataType) if mappedValue is not None: mappedAttributes[name] = mappedValue else: ## No value found... if isRequired is not None: ## Value isn't required, continue parsing the next attribute continue else: ## Transform file listed this as required; need to abort runtime.logger.report('No value found for attribute {name!r}; transform file {transformFile!r} listed this as required... skipping object creation.', name=name, transformFile=transformFile) return ## Create the container first, if there is one if (containerId is not None): runtime.results.addObject(containerClass, uniqueId=containerId) ## Create the target object objectId, exists = addObject(runtime, classToCreate, **mappedAttributes) ## If we have a container, link the object to the container if containerId is not None: addLink(runtime, 'Enclosed', containerId, objectId) ## Send results back 1 at a time, to avoid conflicts causing a DB rollback runtime.logger.report(' result to send: {result!r}', result=runtime.results.getJson()) runtime.sendToKafka() ## end startNormalization return
def createAndMapAliases(runtime, targetId, targetName, targetDomain, trackedZones, domainDict, knownCnames): """Create and link associated aliases.""" try: runtime.logger.report(' Looking for aliases of {targetName!r}', targetName=targetName) ## Map through aliases if any exist if targetDomain in domainDict.keys(): domainCnameDict = domainDict[targetDomain] if targetName in domainCnameDict.keys(): (sourceName, sourceDomain) = domainCnameDict[targetName] runtime.logger.report( ' {targetName!r} has related alias {sourceName!r}', targetName=targetName, sourceName=sourceName) knownCnames[targetName] = 1 ## Create the zone if necessary if sourceDomain not in trackedZones.keys(): ## Add the zone onto (or back onto) the result set zoneId, exists = addObject(runtime, 'Domain', name=sourceDomain) trackedZones[sourceDomain] = zoneId zoneId = trackedZones[sourceDomain] ## Create the record sourceId, exists = addObject(runtime, 'NameRecord', name=sourceName, value=targetName) addLink(runtime, 'Enclosed', zoneId, sourceId) addLink(runtime, 'Route', sourceId, targetId) ## See if there are aliases for this alias createAndMapAliases(runtime, sourceId, sourceName, sourceDomain, trackedZones, domainDict, knownCnames) except: stacktrace = traceback.format_exception(sys.exc_info()[0], sys.exc_info()[1], sys.exc_info()[2]) runtime.logger.error('Failure in createAndMapAliases: {stacktrace!r}', stacktrace=stacktrace) ## end createAndMapAliases return
def trackCertificate(runtime, ipAddress, ipObjectId, port, cert): """Create the IP, Port, and SSLCertificate.""" addObject(runtime, 'IpAddress', uniqueId=ipObjectId) ## Create TcpIpPort tcpIpPortId, portExists = addObject(runtime, 'TcpIpPort', name=str(port), port=int(port), ip=ipAddress, port_type='tcp', is_tcp=True) ## Create SSLCertificate sslCertificateId, certExists = addObject(runtime, 'SSLCertificate', **cert) ## Links addLink(runtime, 'Enclosed', ipObjectId, tcpIpPortId) addLink(runtime, 'Enclosed', tcpIpPortId, sslCertificateId)
def trackCiToCreate(runtime, ipObjectId, ciSection, attributes): """Create the custom CI defined by the mapping definition.""" ciType = ciSection.get('type') staticAttributes = ciSection.get('staticAttributes', {}) ## Add any static attributes for attr, value in staticAttributes.items(): if attr not in attributes: attributes[attr] = value.strip() runtime.logger.report( 'trackCiToCreate: create attributes on {} CI: {}'.format( ciType, attributes)) ## Create the object and link the IP objectId, exists = addObject(runtime, ciType, **attributes) addLink(runtime, 'Usage', objectId, ipObjectId) ## end trackCiToCreate return
def createObjects(runtime, output, processFile, nodeId, ipaddress, hostname, domain): """Grouping two different send methods in this function. The first method formats the content as expected for our internal database, and either implicitely or explicitely sends it back to the framework. The second method formats it in another way and sends it to a different topic on the bus (Kafka), to be consumed by a external endpoint. """ ## Create file objects in the format for the CMS to consume; these ## objects are implicitely sent back after the startJob function returns ## =================================================================== ## Map properties from commands into attributes for the CMS object attributes = {} setAttribute(attributes, 'name', 'Python') setAttribute(attributes, 'version', output, 256) #setAttribute(attributes, 'recorded_by', 'shell_qualify_python', 256) setAttribute(attributes, 'recorded_by', __name__, 256) setAttribute(attributes, 'path', processFile, 256) ## Create the software and link it to the node softwareId = addObject(runtime, 'SoftwarePackage', **attributes) addLink(runtime, 'Enclosed', nodeId, softwareId) ## The above results are tracked by the runtime object, and returned ## after the job finishes. Alternatively, you can explicitely send them ## back by calling the sendToKafka function without any arguments: #runtime.sendToKafka() ## But if you do that, make sure to put the node object back on for the ## next SoftwarePackage object to be linked to the node object again: #runtime.results.addObject('Node', uniqueId=nodeId) ## =================================================================== ## Now send explicitely to a different kafka topic, using any format you ## wish; illustrating streaming multiple outputs for different consumers ## =================================================================== customFormat = { 'hostname' : hostname, 'domain' : domain, 'ipaddress' : ipaddress, 'software' : 'Python', 'version' : output, 'path' : processFile } runtime.sendToKafka('security', customFormat)
def createObjects(runtime, shortname, domain, description, deviceOID, location, firmware, serialNumber, model, assetId, endpoint, ips, protocolId): """Create objects and links in our results.""" try: ## First create the node nodeId, exists = addObject(runtime, 'Node', hostname=shortname, domain=domain, description=description, snmp_oid=deviceOID, location=location) ## Now create the hardware if serialNumber is not None: hardwareId, exists = addObject(runtime, 'HardwareNode', serial_number=serialNumber, bios_info=firmware, model=model, asset_tag=assetId) addLink(runtime, 'Usage', nodeId, hardwareId) ## Now create the IPs for ip in ips: with suppress(ValueError): ipId, exists = addIp(runtime, address=ip) addLink(runtime, 'Usage', nodeId, ipId) ## In case the IP we've connected in on isn't in the IP table list: if endpoint not in ips: with suppress(ValueError): ipId, exists = addIp(runtime, address=endpoint) addLink(runtime, 'Usage', nodeId, ipId) ## Now create the SNMP object realm = runtime.jobMetaData.get('realm') snmpId, exists = addObject(runtime, 'SNMP', container=nodeId, ipaddress=endpoint, protocol_reference=protocolId, realm=realm, node_type='Unknown') addLink(runtime, 'Enclosed', nodeId, snmpId) ## Update the runtime status to success runtime.status(1) except: runtime.setError(__name__) ## end createObjects return
def createObjects(runtime, osAttrDict, biosAttrDict, csAttrDict, ipAddresses, endpoint, protocolId): """Create objects and links in our results.""" try: ## First create the node domain = csAttrDict.get('Domain', None) hostname = csAttrDict.get('Name', None) vendor = osAttrDict.get('Manufacturer', None) platform = osAttrDict.get('Caption', None) version = osAttrDict.get('Version', None) hw_provider = csAttrDict.get('Manufacturer', None) nodeId, exists = addObject(runtime, 'Node', hostname=hostname, domain=domain, vendor=vendor, platform=platform, version=version, hardware_provider=hw_provider) ## Now create the IPs for ip in ipAddresses: with suppress(ValueError): ipId, exists = addIp(runtime, address=ip) addLink(runtime, 'Usage', nodeId, ipId) ## In case the IP we've connected in on isn't in the IP table list: if endpoint not in ipAddresses: with suppress(ValueError): ipId, exists = addIp(runtime, address=endpoint) addLink(runtime, 'Usage', nodeId, ipId) ## Now create the WMI object realm = runtime.jobMetaData.get('realm') snmpId, exists = addObject(runtime, 'WMI', container=nodeId, ipaddress=endpoint, protocol_reference=protocolId, realm=realm, node_type='Windows') addLink(runtime, 'Enclosed', nodeId, snmpId) ## Now create the hardware serial_number = biosAttrDict.get('SerialNumber', None) bios_info = biosAttrDict.get('Caption', None) model = csAttrDict.get('Model', None) manufacturer = csAttrDict.get('Manufacturer', None) hardwareId, exists = addObject(runtime, 'HardwareNode', serial_number=serial_number, bios_info=bios_info, model=model, vendor=manufacturer) addLink(runtime, 'Usage', nodeId, hardwareId) ## Update the runtime status to success runtime.status(1) except: runtime.setError(__name__) ## end createObjects return
def processResults(runtime, client, mappingEntries): """Get nodes & hardware objects passed in and check for matches.""" try: ## Get node attributes coming in identifier = runtime.endpoint.get('identifier') node = runtime.endpoint.get('children').get('Node', [])[0] prevNodeData = node.get('data', {}) nodeName = prevNodeData.get('hostname') nodeId = node.get('identifier') deviceOID = prevNodeData.get('snmp_oid') runtime.logger.report('Processing node {} with snmp_oid {}'.format( nodeName, deviceOID)) if deviceOID is None: raise ValueError( 'Node {} snmp_oid attribute is empty; cannot compare'.format( nodeName)) ## Get hardware attributes coming in hardware = None prevHardwareData = {} hardwareId = None nodeHardwareList = node.get('children').get('Hardware', []) if len(nodeHardwareList) > 0: hardware = nodeHardwareList[0] prevHardwareData = hardware.get('data', {}) hardwareId = hardware.get('identifier') ## Dictionaries for our attribute-to-value mapping here newNodeData = {} newHardwareData = {} objectTypes = {} foundMatch = False ## Loop through the mapping entries for entry in mappingEntries: ref = entry.get('descriptor') matchingSection = entry.get('matchingSection', {}) ## Matching section snmpOID = matchingSection.get('snmpOID') comparisonOperator = matchingSection.get('comparisonOperator') comparisonValue = matchingSection.get('comparisonValue') if comparisonOperator == '==': if deviceOID != snmpOID: continue elif comparisonOperator.lower() == 'regex': escapedOID = snmpOID.replace('.', '[.]') value = comparisonValue.replace('snmpOID', escapedOID, re.I) if not re.search(value, deviceOID): continue else: runtime.logger.warn( 'Unknown compare type for mapping {}. Received {} and expected either "==" or "regEx".' .format(ref, comparisonOperator)) continue foundMatch = True runtime.logger.report(' Matched section: {}'.format(ref)) ## Mapping section mappingSection = entry.get('mappingSection', {}) processThisMappingSection(runtime, client, mappingSection, objectTypes, prevNodeData, prevHardwareData, newNodeData, newHardwareData) ## We already matched break if foundMatch: ## Update the objects/links thisNode = None thisHardware = None if len(newNodeData) > 0: ## Update the node thisNode, exists = addObject(runtime, 'Node', uniqueId=nodeId, **newNodeData) if len(newHardwareData) > 0: if hardwareId is None: ## Create a new hardware object thisHardware, exists = addObject( runtime, objectTypes.get('hardware', 'Hardware'), **newHardwareData) else: ## Update the previous hardware thisHardware, exists = addObject( runtime, objectTypes.get('Hardware'), uniqueId=hardwareId, **newHardwareData) addLink(runtime, 'Usage', thisNode, thisHardware) else: runtime.logger.report( 'No match found on node {} with snmp_oid {}'.format( nodeName, deviceOID)) runtime.setInfo( 'No match found on node {} with snmp_oid {}'.format( nodeName, deviceOID)) except: runtime.setError(__name__) ## end processResults return
def createObjects(runtime, osType, osAttrDict, biosAttrDict, nameAttrDict, ipAddresses, ipDict, endpoint, protocolReference): """Create objects and links in our results.""" protocolId = None try: ## Log when the 'printDebug' parameter is set runtime.logger.report('osAttrDict : {osAttrDict!r}', osAttrDict=osAttrDict) runtime.logger.report('biosAttrDict: {biosAttrDict!r}', biosAttrDict=biosAttrDict) runtime.logger.report('nameAttrDict : {nameAttrDict!r}', nameAttrDict=nameAttrDict) runtime.logger.report('ipAddresses : {ipAddresses!r}', ipAddresses=ipAddresses) ## First create the node domain = nameAttrDict.get('domain') hostname = nameAttrDict.get('hostname') manufacturer = biosAttrDict.get('manufacturer') nodeAttributes = {} for thisAttr in ['distribution', 'platform', 'version', 'kernel']: thisValue = osAttrDict.get(thisAttr) if thisValue is not None: nodeAttributes[thisAttr] = thisValue nodeAttributes['hardware_provider'] = manufacturer nodeId = None if domain is None: nodeId, exists = addObject(runtime, osType, hostname=hostname, **nodeAttributes) else: nodeId, exists = addObject(runtime, osType, hostname=hostname, domain=domain, **nodeAttributes) ## Establish an FQDN string for local IP addresses (loopback) realm = runtime.jobMetaData.get('realm', 'NA') FQDN = 'NA' if hostname is not None: FQDN = hostname if (domain is not None and domain not in hostname): FQDN = '{}.{}'.format(hostname, domain) ## Now create the IPs trackedZones = {} for ip in ipAddresses: ipId = None if (ip in ['127.0.0.1', '::1', '0:0:0:0:0:0:0:1']): ## Override the realm setting for two reasons: we do not want these ## IPs in endpoint query results, and we want to track one per node ipId, exists = runtime.results.addIp(address=ip, realm=FQDN) else: ipId, exists = runtime.results.addIp(address=ip, realm=realm) ## Add any DNS records found if ip in ipDict: for entry in ipDict[ip]: (domainName, recordData) = entry ## Create the zone if necessary if domainName not in trackedZones: ## Add the zone onto the result set zoneId, exists = addObject(runtime, 'Domain', name=domainName) trackedZones[domainName] = zoneId zoneId = trackedZones[domainName] ## Create the DNS record recordId, exists = addObject(runtime, 'NameRecord', name=recordData, value=ip) addLink(runtime, 'Enclosed', zoneId, recordId) addLink(runtime, 'Usage', nodeId, ipId) ## In case the IP we've connected in on isn't in the IP table list: if endpoint not in ipAddresses: ipId, exists = addIp(runtime, address=endpoint) addLink(runtime, 'Usage', nodeId, ipId) ## Now create the SSH object protocolId, exists = addObject(runtime, 'SSH', container=nodeId, ipaddress=endpoint, protocol_reference=protocolReference, realm=realm, node_type=osType) addLink(runtime, 'Enclosed', nodeId, protocolId) ## Now create the hardware serial_number = biosAttrDict.get('serial_number') bios_info = biosAttrDict.get('bios_info') model = biosAttrDict.get('model') manufacturer = biosAttrDict.get('manufacturer') uuid = biosAttrDict.get('uuid') if serial_number is not None: hardwareId, exists = addObject(runtime, 'HardwareNode', serial_number=serial_number, bios_info=bios_info, model=model, vendor=manufacturer, uuid=uuid) addLink(runtime, 'Usage', nodeId, hardwareId) ## Update the runtime status to success runtime.status(1) except: runtime.setError(__name__) ## end createObjects return protocolId