def _checkDbInfo(testSuiteObj, testName, dbConObj, diskId): """ Dump the information in ngas_disks, ngas_files and ngas_files_retired in connection with the disk and compare the results to reference dumps. testSuiteObj: Test suite object (ngamsTestSuite) testName: Name of the test case (string). dbConObj: DB connection object (ngamsDb). diskId: ID of disk to retire (string). Returns: Void. """ # ngas_disks: tmpDiskInfo = ngamsDiskInfo.ngamsDiskInfo().read(dbConObj, diskId) diskInfoBuf = filterOutLines( tmpDiskInfo.dumpBuf(), ["InstallationDate:", "AvailableMb:", "TotalDiskWriteTime:"]) refStatFile = "ref/ngasRetireDisk_%s_1" % testName tmpStatFile = saveInFile(None, diskInfoBuf) testSuiteObj.checkFilesEq(refStatFile, tmpStatFile, "Incorrect/missing info in ngas_disks") # ngas_files: query = "SELECT %s FROM ngas_files nf WHERE disk_id='%s'" %\ (ngamsDb._ngasFilesCols, diskId) curObj = dbConObj.dbCursor(query) fileInfoBuf = "" while (1): res = curObj.fetch(1) if (res == []): break tmpFileInfo = ngamsFileInfo.ngamsFileInfo().unpackSqlResult(res[0]) fileInfoBuf += filterOutLines( tmpFileInfo.dumpBuf(), ["IngestionDate:", "CreationDate:"]) + "\n" refStatFile = "ref/ngasRetireDisk_%s_2" % testName tmpStatFile = saveInFile(None, fileInfoBuf) testSuiteObj.checkFilesEq(refStatFile, tmpStatFile, "Incorrect/missing info in ngas_files") # ngas_files_retired: query = "SELECT %s FROM ngas_files_retired nf WHERE disk_id='%s'" %\ (ngamsDb._ngasFilesCols, diskId) curObj = dbConObj.dbCursor(query) fileInfoBuf = "" while (1): res = curObj.fetch(1) if (res == []): break tmpFileInfo = ngamsFileInfo.ngamsFileInfo().unpackSqlResult(res[0]) fileInfoBuf += filterOutLines( tmpFileInfo.dumpBuf(), ["IngestionDate:", "CreationDate:"]) + "\n" refStatFile = "ref/ngasRetireDisk_%s_3" % testName tmpStatFile = saveInFile(None, fileInfoBuf) testSuiteObj.checkFilesEq(refStatFile, tmpStatFile, "Incorrect/missing info in ngas_files")
def getDiskInfoObjsFromMimeType(hostId, dbConObj, ngamsCfgObj, mimeType, sendNotification=1): """ Get the Disk Info for the disks allocated related to a certain mime-type/stream. dbConObj: DB connection object (ngamsDb). ngamsCfgObj: NG/AMS Configuration Object (ngamsConfig). mimeType: Mime-type (string). sendNotification: 1 = send email notification message in case no disks are found (integer). Returns: List of Disk Info Objects (list/ngamsDiskInfo). """ T = TRACE() stream = ngamsCfgObj.getStreamFromMimeType(mimeType) if (stream == None): errMsg = genLog("NGAMS_AL_NO_STO_SETS", [mimeType]) raise Exception, errMsg slotIds = [] for id in stream.getStorageSetIdList(): set = ngamsCfgObj.getStorageSetFromId(id) slotIds.append(set.getMainDiskSlotId()) if (set.getRepDiskSlotId() != ""): slotIds.append(set.getRepDiskSlotId()) diskInfo = dbConObj.getDiskInfoForSlotsAndHost(hostId, slotIds) if (diskInfo == []): errMsg = genLog("NGAMS_AL_NO_STO_SETS", [mimeType]) logger.warning(errMsg) if (sendNotification): ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_NO_DISKS, "NO STORAGE SET (DISKS) AVAILABLE", errMsg) raise Exception, errMsg # Unpack the disk information into ngamsDiskInfo objects. diskInfoObjs = [] for diRaw in diskInfo: tmpDiskInfo = ngamsDiskInfo.ngamsDiskInfo().unpackSqlResult(diRaw) diskInfoObjs.append(tmpDiskInfo) return diskInfoObjs
def markDiskAsUmountedInDb(hostId, dbConObj, diskId): """ Mark a disk as unmounted in the NGAS DB. dbConObj: DB connection object (ngamsDb). diskId: Disk ID (string). Returns: Void. """ logger.info("Marking disk with ID: %s as unmounted in the NGAS DB", diskId) diskInfoObj = ngamsDiskInfo.ngamsDiskInfo() diskInfoObj.read(dbConObj, diskId).\ setHostId("").setSlotId("").setMounted(0).\ setMountPoint("").setLastHostId(hostId).\ write(dbConObj) logger.info("Marked disk with ID: %s as unmounted in the NGAS DB ...", diskId)
def dumpDiskInfo(hostId, dbConObj, ngamsCfgObj, diskId, mountPoint): """ Dump the disk status information for one disk. hostId: The ID of this NGAS host dbConObj: DB connection object (ngamsDb). ngamsCfgObj: NG/AMS Configuration Object (ngamsConfig). diskId: Disk ID (string). mountPoint: Mount point (string). Returns: NgasDiskInfo XML document (string/xml). """ # Get disk info from DB diskInfo = ngamsDiskInfo.ngamsDiskInfo() try: diskInfo.read(dbConObj, diskId) except: errMsg = genLog("NGAMS_ER_DISK_STATUS", [diskId]) logger.error(errMsg) ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_ERROR, "MISSING DISK IN DB", errMsg) return # Create status object and save the XML in the status file ngasDiskInfo = prepNgasDiskInfoFile(hostId, diskInfo) filename = os.path.normpath(mountPoint + "/" + NGAMS_DISK_INFO) # Check if it is possible to write in the file if it exists. if (os.path.exists(filename) and (not ngamsLib.fileWritable(filename))): return logger.debug("Writing NGAS Disk Status for disk with ID: %s into file: %s", diskId, filename) fd = open(filename, "w") fd.write(ngasDiskInfo) fd.close() return ngasDiskInfo
def getDiskInfoForMountedDisks(dbConObj, hostId, mtRootDir): """ Retrieve a list of disk entries from the ngas_disks table which appear to be mounted for this system. dbConObj: DB connection object (ngamsDb). host: Host name (string). mtRootDir: Base mount directory for NG/AMS (string). Returns: List containing the ngamsDiskInfo elements for the disks registered as mounted in this system (list). """ T = TRACE() diskIds = dbConObj.getDiskIdsMountedDisks(hostId, mtRootDir) diskList = [] for diskId in diskIds: diskInfo = ngamsDiskInfo.ngamsDiskInfo() diskInfo.read(dbConObj, diskId) diskList.append(diskInfo) return diskList
def updateDiskStatusDb(dbConObj, piStat): """ Updates the information in connection with a disk when it comes to the number of files stored, the available space, bytes stored and the total I/O time. Checksum not yet supported. dbConObj: DB connection object (ngamsDb). piStat: Status as returned by the DAPIs (ngamsDapiStatus). Returns: Disk Info Object (ngamsDiskInfo). """ logger.debug("Updating disk status for disk with ID: %s", piStat.getDiskId()) global _ngamsDisksSem _ngamsDisksSem.acquire() diskInfo = ngamsDiskInfo.ngamsDiskInfo() diskInfo.read(dbConObj, piStat.getDiskId()) # Increment only the number of files (stored on the disk), if a # new file (not already existing in this environment) was stored. if (not piStat.getFileExists()): diskInfo.setNumberOfFiles(diskInfo.getNumberOfFiles() + 1) diskInfo.setAvailableMb(getDiskSpaceAvail(diskInfo.getMountPoint())) diskInfo.setBytesStored(diskInfo.getBytesStored() + piStat.getFileSize()) diskInfo.setTotalDiskWriteTime(diskInfo.getTotalDiskWriteTime() +\ piStat.getIoTime()) diskInfo.write(dbConObj) _ngamsDisksSem.release() logger.debug("Updated disk status for disk with ID: %s", piStat.getDiskId()) return diskInfo
def deleteDiskInfo(self, diskId, delFileInfo=1): """ Delete a record for a certain disk in the NGAS DB. CAUTION: IF THE DB USER WITH WHICH THERE IS LOGGED IN HAS PERMISSION TO EXECUTE DELETE STATEMENTS, THE INFORMATION ABOUT THE DISK IN THE NGAS DB WILL BE DELETED! THIS INFORMATION CANNOT BE RECOVERED!! diskId: ID of disk for which to delete the entry (string). delFileInfo: If set to 1, the file information for the files stored on the disk is deleted as well (integer/0|1). Returns: Reference to object itself. """ T = TRACE() fileInfoDbmName = None fileInfoDbm = None try: # Get the information about the files on the disk (before this # information is deleted). if delFileInfo and self.getCreateDbSnapshot(): diskInfo = ngamsDiskInfo.ngamsDiskInfo().read(self, diskId) fileInfoDbmName = self.genTmpFile('DISK_INFO') fileInfoDbm = ngamsDbm.ngamsDbm(fileInfoDbmName, cleanUpOnDestr=0, writePerm=1) fileCount = 0 for fileInfo in self.getFileInfoList(diskId, fetch_size=1000): fileInfoDbm.add(str(fileCount), fileInfo) fileCount += 1 fileInfoDbm.sync() # Delete the disk info. sql = "DELETE FROM ngas_disks WHERE disk_id={}" self.query2(sql, args=(diskId, )) # Delete file info if requested. if delFileInfo: sql = "DELETE FROM ngas_files WHERE disk_id={}" self.query2(sql, args=(diskId, )) # Create a File Removal Status Document. if (self.getCreateDbSnapshot()): op = NGAMS_DB_CH_FILE_DELETE fileInfoDbm.initKeyPtr() key, fileSqlInfo = fileInfoDbm.getNext() while (key): tmpFileObj = ngamsFileInfo.ngamsFileInfo().\ unpackSqlResult(fileSqlInfo) self.createDbRemFileChangeStatusDoc( diskInfo, tmpFileObj) key, fileSqlInfo = fileInfoDbm.getNext() self.triggerEvents( [diskInfo.getDiskId(), diskInfo.getMountPoint()]) return self except Exception: logger.exception("Error deleting disk info from DB") raise finally: if fileInfoDbm: del fileInfoDbm if fileInfoDbmName: rmFile(fileInfoDbmName)
def retireDisk(diskId, force, execute, notifEmail): """ Remove file entries from the ngas_files DB, which are stored on disks having the mount point column set to 'RETIRED'. diskId: Disk ID of disk to retire (string). execute: Execute the command. If set to 0, the command is executed otherwise it is only checked if the command can be executed (integer/0|1). force: Even though there are less than 3 copies of each file on the disk in the system or even if the disk is mounted retire the disk (integer/0|1). notifEmail: Comma separated list of email recipients that should be informed about the actions carried out, or the actions that would be carried out if executing the command (integer/0|1). Returns: Void. """ info(0,"Executing Retire Disk Procedure on disk with ID: %s" % diskId) # Open DB connection. info(3,"Open DB connection") server, db, user, password = ngasUtilsLib.getDbPars() dbCon = ngamsDb.ngamsDb(server, db, user, password, 0) # Dummy server object, needed by one of the methods used ... srvObj = ngamsServer.ngamsServer().setDb(dbCon) # Get information about the disk. info(3,"Get info about disk in question") sqlDiskInfo = dbCon.getDiskInfoFromDiskId(diskId) if (sqlDiskInfo == []): raise Exception, "Disk ID given: %s not found in the NGAS DB!" % diskId diskInfoObj = ngamsDiskInfo.ngamsDiskInfo().unpackSqlResult(sqlDiskInfo) info(0,"Disk with ID: %s has Logical Name: %s" %\ (diskInfoObj.getDiskId(), diskInfoObj.getLogicalName())) # Check if the disk is marked as mounted, in case yes, reject it. if (diskInfoObj.getMounted()): errMsg = "Disk with ID: %s is marked as mounted in the DB! "+\ "Rejecting request." raise Exception, errMsg % diskId # Check if there are at least three copies of each file. if (not force): basePath = "/tmp/.ngasRetireDisk" checkCreatePath(basePath) ngasUtilsLib.checkDelTmpDirs(basePath + "/*") tmpPath = "/tmp/.ngasRetireDisk/" + str(time.time()) checkCreatePath(tmpPath) dbFilePat = tmpPath + "/DBM" lessCopyDbm, notRegDbm, allFilesDbm =\ ngamsRemUtils.checkFileCopiesAndReg(srvObj, 3, dbFilePat, None, diskId, 1) srvObj.getCfg().storeVal("NgamsCfg.Notification[1].SmtpHost", "smtphost.hq.eso.org") reqPropsObj = ngamsReqProps.ngamsReqProps().\ setCmd("ngasRetireDisk").\ addHttpPar("notif_email", notifEmail).\ addHttpPar("disk_id", diskId) status = ngamsRemUtils._remStatErrReport(srvObj, reqPropsObj, dbFilePat, lessCopyDbm, notRegDbm, allFilesDbm, diskId) commands.getstatusoutput("rm -rf " + dbFilePat + "*") if (status): errMsg = "Cannot retire disk with ID: %s - one or more files " +\ "are not available in at least 3 copies!" raise Exception, errMsg % diskId # First query the files in question. info(0,"Get list of files stored on disk: %s ..." %\ diskInfoObj.getLogicalName()) query = "SELECT nf.disk_id, file_id, file_version " +\ "FROM ngas_files nf, ngas_disks nd WHERE " +\ "nd.disk_id='%s' AND nf.disk_id='%s'" query = query % (diskId, diskId) statFileList = dbCon.query(query, 1) info(0,"Got list of files stored on disk: %s" %\ diskInfoObj.getLogicalName()) # Back-up the files on the retired disk to the ngas_files_retired table. if (execute): info(0,"Insert files on Retired Disk into ngas_files_retired") query = "INSERT INTO ngas_files_retired SELECT disk_id, " +\ "file_name, file_id, file_version, format, file_size, " +\ "uncompressed_file_size, compression, ingestion_date, " +\ "file_ignore, checksum, checksum_plugin, file_status, " +\ "creation_date FROM ngas_files WHERE disk_id='%s'" query = query % diskId dbCon.query(query, 1) info(0,"Inserted files on Retired Disk into ngas_files_retired") # Remove the entries from the DB. if (execute): info(0,"Remove entry from disk from DB ...") query = "DELETE FROM ngas_files WHERE disk_id='%s'" % diskId dbCon.query(query, 1) info(0,"Removed entry from disk from DB") # Set the mount point of the referenced disk to 'RETIRED'. if (execute): info(0,"Setting mount point of Retired Disk to 'RETIRED' ...") query = "UPDATE ngas_disks SET mount_point='RETIRED' WHERE " +\ "disk_id='%s'" query = query % diskId dbCon.query(query, 1) info(0,"Set mount point of Retired Disk to 'RETIRED'") # Generate report. if (notifEmail): info(0,"Generate DISK RETIREMENT STATUS REPORT ...") report = "DISK RETIREMENT STATUS REPORT - %s:\n\n" % diskId if (not execute): report += "Information for disk/files concerned if command " +\ "is executed.\n\n" else: report += "Information for disk/files concerned.\n\n" report += "Date: %s\n" % PccUtTime.TimeStamp().getTimeStamp() report += "NGAS Host: %s\n" % getHostName() report += "Disk ID: %s\n\n" % diskId tmpFormat = "%-32s %-32s %-12s\n" report += tmpFormat % ("Disk ID", "File ID", "File Version") report += tmpFormat % (32 * "-", 32 * "-", 12 * "-") if (len(statFileList[0])): for fileInfo in statFileList[0]: report += tmpFormat % (fileInfo[0], fileInfo[1], fileInfo[2]) else: report += "No files found on disk!\n" report += 78 * "-" + "\n" subject = "ngasRetireDisk: DISK RETIREMENT REPORT - %s" % diskId ngasUtilsLib.sendEmail(subject, notifEmail, report) info(0,"Generated DISK RETIREMENT STATUS REPORT") info(0,"Finished Disk Retirement Procedure for disk: %s/%s" %\ (diskInfoObj.getDiskId(), diskInfoObj.getLogicalName()))
def unpackXmlDoc(self, doc, getStatus=0, ignoreVarDiskPars=0): """ Unpack a status report stored in an XML document and set the members of the class accordingly. doc: Status report as XML document (string). getStatus: Extract also the status information from the XML document (0|1/integer). ignoreVarDiskPars: Ignore the variable part of the disk status: Host ID, Slot ID, Mounted, Mount Point (integer/0|1). Returns: Reference to object itself. """ dom = xml.dom.minidom.parseString(doc) ngamsStatusEl = ngamsGetChildNodes(dom, NGAMS_XML_STATUS_ROOT_EL)[0] # Get the information from the Status Element. nodeList = dom.getElementsByTagName("Status") self.setDate(getAttribValue(nodeList[0], "Date")) self.setVersion(getAttribValue(nodeList[0], "Version")) self.setHostId(getAttribValue(nodeList[0], "HostId")) if (getStatus): self.setStatus(getAttribValue(nodeList[0], "Status")) self.setMessage(getAttribValue(nodeList[0], "Message")) if (getStatus): self.setState(getAttribValue(nodeList[0], "State")) self.setSubState(getAttribValue(nodeList[0], "SubState")) # Get the optional request handling status. requestId = getAttribValue(nodeList[0], "RequestId", 1) if (requestId): self.setRequestId(requestId) requestTime = getAttribValue(nodeList[0], "RequestTime", 1) if (requestTime): self.setRequestTime(fromiso8601(requestTime)) completionPercent = getAttribValue(nodeList[0], "CompletionPercent", 1) if (completionPercent): self.setCompletionPercent(completionPercent) expectedCount = getAttribValue(nodeList[0], "ExpectedCount", 1) if (expectedCount): self.setExpectedCount(expectedCount) actualCount = getAttribValue(nodeList[0], "ActualCount", 1) if (actualCount): self.setActualCount(actualCount) estTotalTime = getAttribValue(nodeList[0], "EstTotalTime", 1) if (estTotalTime): self.setEstTotalTime(float(estTotalTime)) remainingTime = getAttribValue(nodeList[0], "RemainingTime", 1) if (remainingTime): self.setRemainingTime(float(remainingTime)) lastRequestStatUpdate = getAttribValue(nodeList[0], "LastRequestStatUpdate", 1) if (lastRequestStatUpdate): self.setLastRequestStatUpdate(fromiso8601(lastRequestStatUpdate)) completionTime = getAttribValue(nodeList[0], "CompletionTime", 1) if (completionTime): self.setCompletionTime(fromiso8601(completionTime)) # Unpack the NG/AMS Configuration information. ngamsCfgRootNode = dom.getElementsByTagName("NgamsCfg") if (len(ngamsCfgRootNode) > 0): tolerant = 1 self.__ngamsCfg.unpackFromRootNode(ngamsCfgRootNode[0], tolerant) # Unpack Disk Status Elements and File Status Elements. diskNodes = dom.getElementsByTagName("DiskStatus") for diskNode in diskNodes: diskInfo = ngamsDiskInfo.ngamsDiskInfo().\ unpackFromDomNode(diskNode, ignoreVarDiskPars) self.addDiskStatus(diskInfo) # Unpack File Lists. fileListNodes = dom.getElementsByTagName("FileList") for fileListNode in fileListNodes: fileListObj = ngamsFileList.ngamsFileList() self.addFileList(fileListObj) fileListObj.unpackFromDomNode(fileListNode) # Unpack Containers. Loop over the root containers, # then let them deal with their own recursion rootContainerEls = [node for node in ngamsStatusEl.childNodes \ if node.nodeType == xml.dom.minidom.Node.ELEMENT_NODE\ and node.tagName == 'Container'] for rootContainerEl in rootContainerEls: container = ngamsContainer.ngamsContainer() container.unpackFromDomNode(rootContainerEl) self.addContainer(container) dom.unlink() return self
def changeDiskLabel(diskId, newLabel=None, execute=0): """ Change the Disk Label (ngas_disks.logical_name) of the disk referred to by its Disk ID. diskId: Disk ID of the disk (string). newLabel: New label to allocate to the disk (string). execute: Execute the change (integer/0|1). Returns: Void. """ # Open DB connection. server, db, user, password = ngasUtilsLib.getDbPars() dbCon = ngamsDb.ngamsDb(server, db, user, password, 0) # Now, loop and ask the user to enter the new label and to confirm when OK. while (1): sqlDiskInfo = dbCon.getDiskInfoFromDiskId(diskId) if (not sqlDiskInfo): msg = "Disk with ID: %s appears not to be known to this system!" raise Exception, msg % diskId diskInfoObj = ngamsDiskInfo.ngamsDiskInfo().\ unpackSqlResult(sqlDiskInfo) orgDiskLabel = diskInfoObj.getLogicalName() print "Present Disk Label: %s" % orgDiskLabel if (newLabel): newDiskLabel = newLabel else: newDiskLabel = ngasUtilsLib.input("Enter new Disk Label:") if (sqlDiskInfo == []): raise Exception, "Disk ID given: %s not found in the NGAS DB!" %\ diskId print "\nChanging Disk Label for Disk with:" print " - Disk ID: " + diskId print " - Disk Label: " + orgDiskLabel print " - New Disk Label: " + newDiskLabel + "\n" if (execute): break else: choice = ngasUtilsLib.input("Is this correct (Y/N) [N]?").upper() if (choice == "Y"): break print "Changing Disk Label from %s to %s ..." %\ (orgDiskLabel, newDiskLabel) # Check if this disk label already has been allocated. logNames = dbCon.getLogicalNamesMountedDisks(getHostName()) for logName in logNames: if (logName == newDiskLabel): raise Exception, "Disk Label: %s is already in use!" % newDiskLabel diskInfoObj.setLogicalName(newDiskLabel).write(dbCon) sqlDiskInfo = dbCon.getDiskInfoFromDiskId(diskId) diskInfoObj = ngamsDiskInfo.ngamsDiskInfo().unpackSqlResult(sqlDiskInfo) report = "DISK LABEL CHANGE REPORT:\n\n" msg = "Changed Disk Label from %s to %s - new disk status:" %\ (orgDiskLabel, newDiskLabel) report += msg + "\n\n" print msg msg = diskInfoObj.dumpBuf() report += msg + "\n\n" print msg print("\nPut the given disk Online/reboot the host in " +\ "which the disk is inserted." "\n\nCheck the disk info in the NGAS WEB Interfaces!\n") notifEmail = ngasUtilsLib.\ getParNgasRcFile(ngasUtilsLib.NGAS_RC_PAR_NOTIF_EMAIL) if (notifEmail): ngasUtilsLib.sendEmail("ngasChangeDiskLabel: DISK LABEL CHANGE REPORT", notifEmail, report)
def findTargetDisk(hostId, dbConObj, ngamsCfgObj, mimeType, sendNotification=1, diskExemptList=[], caching=0, reqSpace=None): """ Find a target disk for a file being received. dbConObj: DB connection object (ngamsDb). ngamsCfgObj: Instance of NG/AMS Configuration Class (ngamsConfig). mimeType: Mime-type of file (string). sendNotification: 1 = send Email Notification Message (integer). diskExemptList: List with Disk IDs of disks, which it is not desirable to consider (list/string). caching: Used to increase the speed of this function if it is invoked many times sequentially. SHOULD BE USED WITH GREAT CARE! (integer/0|1). reqSpace: The required space needed in bytes (integer). Returns: ngamsDiskInfo object containing the necessary information (ngamsDiskInfo). """ T = TRACE() startTime = time.time() # Get Disk IDs matching the mime-type. logger.debug("Finding target disks - mime-type is: %s", mimeType) global _diskInfoObjsDic if ((not caching) or (not _diskInfoObjsDic.has_key(mimeType))): diskInfoObjs = getDiskInfoObjsFromMimeType(hostId, dbConObj, ngamsCfgObj, mimeType, sendNotification) if (caching): _diskInfoObjsDic[mimeType] = diskInfoObjs else: diskInfoObjs = _diskInfoObjsDic[mimeType] # Analyze which of the dynamic Disks Sets are available to be used # as Target Disk Set, i.e., only Disk Sets where both Main Disk and # Replication Disk (if available) are not completed. diskIdDic = {} slotIdDic = {} for diskInfoObj in diskInfoObjs: diskIdDic[diskInfoObj.getDiskId()] = diskInfoObj slotIdDic[diskInfoObj.getSlotId()] = diskInfoObj # If the disk is a Main Disk, and if it is not completed, and if there is # an associated Replication Disk and it is also not completed, we accept # the disk as a possible candidate disk. diskIds = [] for diskInfoObj in diskInfoObjs: # We disregard disks listed in the exemptlist. if diskInfoObj.getDiskId() in diskExemptList: continue # Only a Main Disk (not completed) can be considered. if (isMainDisk(diskInfoObj.getSlotId(), ngamsCfgObj) and (not diskInfoObj.getCompleted())): # Check if the Main Disk has enough space on it to store the file. # Even though a disk is not completed, it may be that there is not # enough space to store a given file. if (reqSpace): if (diskInfoObj.getAvailableMb() < (reqSpace / 1048576.)): continue # If replication is on, check the associated Replication Disk # (if any). repSlotId = ngamsCfgObj.getAssocSlotId(diskInfoObj.getSlotId()) if (ngamsCfgObj.getReplication() and (repSlotId != "") and (slotIdDic.has_key(repSlotId))): repDiskObj = slotIdDic[repSlotId] if (not repDiskObj.getCompleted()): # Check if the Replication Disk has enough space. if (reqSpace): if (repDiskObj.getAvailableMb() < (reqSpace / 1048576.)): continue diskIds.append(diskInfoObj.getDiskId()) else: diskIds.append(diskInfoObj.getDiskId()) # If no storage sets found, generate a log message. if (diskIds == []): errMsg = genLog("NGAMS_AL_NO_STO_SETS", [mimeType]) logger.warning(errMsg) if (sendNotification): ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_NO_DISKS, "NO DISKS AVAILABLE", errMsg) raise Exception, errMsg # Find the best target disk. global _bestTargetDiskDic key = str(diskIds)[1:-1].replace("'", "_").replace(", ", "") if ((not caching) or (not _bestTargetDiskDic.has_key(key))): diskId = dbConObj.getBestTargetDisk(diskIds, ngamsCfgObj.getRootDirectory()) if (caching): _bestTargetDiskDic[key] = diskId else: diskId = _bestTargetDiskDic[key] if (diskId == None): errMsg = genLog("NGAMS_AL_NO_STO_SETS", [mimeType]) logger.warning(errMsg) if (sendNotification): ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_NO_DISKS, "NO DISKS AVAILABLE", errMsg) raise Exception, errMsg else: global _diskInfoDic key = diskId + "_" + mimeType if ((not caching) or (not _diskInfoDic.has_key(key))): diskInfo = ngamsDiskInfo.ngamsDiskInfo() diskInfo.getInfo(dbConObj, ngamsCfgObj, diskId, mimeType) if (caching): _diskInfoDic[key] = diskInfo else: diskInfo = _diskInfoDic[key] return diskInfo
def addDiskInDb(hostId, dbConObj, ngamsCfgObj, slotId, diskDic): """ Add a disk in the NGAS DB. hostId: The ID of this NGAS host dbConObj: DB connection object (ngamsDb). ngamsCfgObj: NG/AMS Configuration Object (ngamsConfig). slotId: Slot ID (string). diskDic: Dictionary containing ngamsPhysDiskInfo objects with the information about the disk configuration (dictionary). Returns: Void. """ T = TRACE() diskId = diskDic[slotId].getDiskId() logger.info( "Adding disk with ID: %s - Slot ID: %s, not registered in the NGAS DB", diskId, slotId) # In the following the assumption is made that if a disk doesn't have an # entry in the NGAS DB, this means that the disk is 'clean', i.e. doesn't # contain files already, or if, then these are not taken into account. installationDate = time.time() logicalName = genLogicalName(hostId, dbConObj, ngamsCfgObj, diskId, slotId) mountPoint = diskDic[slotId].getMountPoint() # Create the disk info element. diskEntry = ngamsDiskInfo.ngamsDiskInfo().\ setArchive(ngamsCfgObj.getArchiveName()).\ setInstallationDate(installationDate).\ setLogicalName(logicalName).\ setHostId(hostId).\ setSlotId(slotId).\ setMounted(1).\ setMountPoint(mountPoint).\ setNumberOfFiles(0).\ setAvailableMb(getDiskSpaceAvail(mountPoint)).\ setBytesStored(0).\ setCompleted(0).\ setChecksum("").\ setTotalDiskWriteTime(0.0).\ setLastHostId(hostId) # Ensure that the values extracted from the disk BIOS are actually taken # from the disk BIOS. diskEntry.setDiskId(diskId).setType(diskDic[slotId].getType()) diskEntry.setManufacturer(diskDic[slotId].getManufacturer()) # Write the information in the DB. addedNewEntry = diskEntry.write(dbConObj) # Add an entry in the NGAS Disks History Table. if (addedNewEntry): dbConObj.addDiskHistEntry( hostId, diskId, "Disk Registered", "text/xml", prepNgasDiskInfoFile(hostId, diskEntry, 1, 1)) logger.info("Added disk with ID: %s in the NGAS DB", diskId)
def checkDisks(hostId, dbConObj, ngamsCfgObj, diskDic): """ First it is checked if all HDDs marked in the DB as mounted in this NGAS system are actually mounted. Check the HDDs currently installed and for each HDD it is checked if there is an entry for this. If not a new entry for this HDD is created. Subsequently it is checked if each of the disks now marked as mounted and thus available in this system, are really available. If not, an exception is thrown. Finally it is checked that for each Stream defined in the NG/AMS Configuration, that the disks of at least one Storage Set are available. hostId: The ID of this NGAS host dbConObj: DB connection object (ngamsDb). ngamsCfgObj: Configuration object (ngamsConfig). diskDic: Dictionary containing ngamsPhysDiskInfo objects with the information about the disk configuration (dictionary). Returns: Void. """ T = TRACE() diskList = getDiskInfoForMountedDisks(dbConObj, hostId, ngamsCfgObj.getRootDirectory()) # The "mtDiskDic" dictionary contains information (ngasDiskInfo objects) # for each disk mounted on this system. if (diskList != []): logger.debug("All System Types: Checking if disks registered in the " +\ "DB as mounted on this system really are mounted physically ...") mtDiskDic = {} for disk in diskList: logger.info("Checking for availability of disk with ID: %s", disk.getDiskId()) found = 0 for slotId in diskDic.keys(): if (diskDic[slotId].getDiskId() == disk.getDiskId()): found = 1 mtDiskDic[slotId] = disk break if (found == 0): logger.info( "Disk with ID: %s not available anymore - modifying entry in DB.", disk.getDiskId()) disk.setHostId("") disk.setSlotId("") disk.setMountPoint("") disk.setMounted(0) disk.write(dbConObj) else: logger.info("Disk with ID: %s available.", disk.getDiskId()) # Ensure we have the information available for each disk, either from the # DB or from the NGAS Disk Info files (if one of these are available). # # Note: If both information about the disk is available in the DB and # in the NgasDiskInfo file, the information for the disk is taken # from the one, which has the most recent InstallationDate defined. slotIdList = [] for slotId in diskDic.keys(): slotIdList.append(slotId) slotIdList.sort() for slotId in slotIdList: slotId = str(slotId) # Get from DB if not already read + if disk in DB. if (not mtDiskDic.has_key(slotId)): if (dbConObj.diskInDb(diskDic[slotId].getDiskId())): dbDiskInfo = ngamsDiskInfo.ngamsDiskInfo() dbDiskInfo.read(dbConObj, diskDic[slotId].getDiskId()) mtDiskDic[slotId] = dbDiskInfo else: dbDiskInfo = mtDiskDic[slotId] # Get info from NgasDiskInfo file (if available). ngasDiskInfoFile = getNgasDiskInfoFile(diskDic, slotId) # Decide which information to use. if (not mtDiskDic.has_key(slotId)): mtDiskDic[slotId] = ngasDiskInfoFile elif (mtDiskDic.has_key(slotId) and ngasDiskInfoFile): # Take the info in the NgasDiskInfo file if this is the most # recent one. if (ngasDiskInfoFile.getInstallationDate() > dbDiskInfo.getInstallationDate()): logger.info("Disk information in NgasDiskInfo File for disk with "+\ "ID: %s / Slot ID: %s, is more recent than the one found in the " +\ "NGAS DB for that disk. Taking information for disk " +\ "from NgasDiskInfo File.", ngasDiskInfoFile.getDiskId(), slotId) mtDiskDic[slotId] = ngasDiskInfoFile else: mtDiskDic[slotId] = None if (ngamsCfgObj.getAllowArchiveReq() and (diskDic != {})): logger.info("Archiving System: Checking that all disks defined in the " +\ "configuration and which are mounted and not completed, can be "+\ "accessed. Check that installed disks, have entries in the " +\ "NGAS DB ...") mtSlotIds = diskDic.keys() cfgSlotIds = [] for cfgSlotId in ngamsCfgObj.getSlotIds(): cfgSlotIds.append(cfgSlotId) cfgSlotIds.sort() notifInfo = [] # Disks, which should not be updated/inserted in the DB are contained # in the "rmDiskDic" dictionary. rmDiskDic = {} # Disks, which should be updated/inserted in the DB are contained # in the "dbUpdateDic" dictionary. dbUpdateDic = {} for slotId in cfgSlotIds: slotId = str(slotId) if slotId in mtSlotIds: diskInfo = diskDic[slotId] assocSlotId = ngamsCfgObj.getAssocSlotId(slotId) # If a disk is marked as 'completed' in the DB or in the # NGAS Disk Info File, we simply update its entry in the DB. if (mtDiskDic[slotId]): if (mtDiskDic[slotId].getCompleted()): logger.info("Disk in Slot with ID: %s " +\ "is marked as 'completed' - just updating " +\ "info in DB", slotId) dbUpdateDic[slotId] = ["UPDATE", mtDiskDic[slotId]] continue # Check for disk accessibility diskRef = "Slot ID: " + str(diskInfo.getSlotId()) +\ " - Disk ID: " + diskInfo.getDiskId() logger.info("Checking for accessibility of disk: %s", diskRef) if (checkDiskAccessibility(diskInfo.getMountPoint()) == -1): errMsg = genLog("NGAMS_ER_DISK_INACCESSIBLE", [diskRef]) logger.error(errMsg) rmDiskDic[slotId] = slotId notifInfo.append(["DISK INACCESSIBLE", errMsg]) if (dbUpdateDic.has_key(assocSlotId)): dbUpdateDic[assocSlotId] = None del dbUpdateDic[assocSlotId] continue else: logger.info("Disk: %s is accessible", diskRef) logger.info( "Check if the disk with ID: %s already has an entry in the DB", diskInfo.getDiskId()) tmpDiskInfo = mtDiskDic[slotId] # Check the disk information or simply mark the disk # for update in the DB. if (tmpDiskInfo == None): # If the associated disk is not already found to be # wrong, we add an ADD entry in the Update DB Dictionary. if (not rmDiskDic.has_key(assocSlotId)): dbUpdateDic[slotId] = ["ADD"] else: logger.info("Entry found in DB for disk with ID: %s", diskInfo.getDiskId()) logger.info("Check that this disk already registered " +\ "is used correctly as Main or Replication Disk ...") # From the Logical Name of the disk, we can identify # if it was previously used as a Main or as a Replication # Disk (e.g.: "LS-FitsStorage3-M-000003"). From the Slot # ID we check via the NG/AMS Configuration if the disk is # installed in a Main or Replication Slot. try: tmpType = tmpDiskInfo.getLogicalName().split("-")[-2] except Exception, e: raise Exception, "Illegal Logical Name specified: " +\ str(tmpDiskInfo.getLogicalName()) + " for " +\ "disk with ID: " + tmpDiskInfo.getDiskId() if (tmpType == "M"): prevMainDisk = 1 else: prevMainDisk = 0 mainDisk = isMainDisk(slotId, ngamsCfgObj) # Check: Disk was previously installed as a Main Disk, # but is now installed in a Replication Slot. if (prevMainDisk and not mainDisk): errMsg = genLog( "NGAMS_ER_MAIN_DISK_WRONGLY_USED", [str(slotId), tmpDiskInfo.getLogicalName()]) logger.error(errMsg) notifInfo.append(["MAIN DISK USED AS " +\ "REPLICATION DISK", errMsg]) rmDiskDic[slotId] = slotId continue # Check: Disk was previously installed as a Replication # Disk, but is now installed in a Main Slot. if (not prevMainDisk and mainDisk): errMsg = genLog( "NGAMS_ER_REP_DISK_WRONGLY_USED", [str(slotId), tmpDiskInfo.getLogicalName()]) logger.error(errMsg) notifInfo.append(["REPLICATION DISK USED AS " +\ "MAIN DISK", errMsg]) rmDiskDic[slotId] = slotId continue # Everything OK, update existing entry in the DB. # If the associated disk is not already found to be # wrong, we add an entry in the Update DB Dictionary. if (not rmDiskDic.has_key(assocSlotId)): dbUpdateDic[slotId] = ["UPDATE", tmpDiskInfo] # Create some standard directories on the disk if not # already there. if (ngamsCfgObj.getAllowArchiveReq() or ngamsCfgObj.getAllowRemoveReq()): diskDbDir = os.path.normpath(diskInfo.getMountPoint() +\ "/" + NGAMS_DB_DIR) checkCreatePath(diskDbDir) diskDbCacheDir = os.path.\ normpath(diskInfo.getMountPoint() +\ "/" + NGAMS_DB_CH_CACHE) checkCreatePath(diskDbCacheDir) # Check that each disk accepted so far has an associated disk if this # is specified like this in the configuration. logger.info("Check if each disk has an associated disk if the " +\ "configuration specifies this ...") for slotId in dbUpdateDic.keys(): # We do not consider disks that are already completed. if (mtDiskDic[slotId]): if (mtDiskDic[slotId].getCompleted()): continue assocSlotId = ngamsCfgObj.getAssocSlotId(slotId) if (assocSlotId): if (not dbUpdateDic.has_key(assocSlotId)): msg = "Disk in slot: %s has no associated " +\ "disk in slot: %s - rejecting disk in slot: %s" logger.info(msg, slotId, assocSlotId, slotId) del dbUpdateDic[slotId] rmDiskDic[slotId] = slotId # Remove entries from the Disk Dictionary, which are invalid. for slId in rmDiskDic.keys(): for id in [slId, ngamsCfgObj.getAssocSlotId(slId)]: if (diskDic.has_key(id)): logger.info("Removing invalid disk info object from Disk " +\ "Dictionary - Port No: %s Mount Point: %s Disk ID: %s", str(diskDic[id].getPortNo()), str(diskDic[id].getMountPoint()), diskDic[id].getDiskId()) diskDic[id] = None del diskDic[id] if (dbUpdateDic.has_key(id)): dbUpdateDic[id] = None del dbUpdateDic[id] # Generate a Notification Message with the possible errors # accumulated so far and send out Error Notification Messages. if (len(notifInfo) > 0): errMsg = "FOLLOWING PROBLEMS WERE ENCOUNTERED WHILE CHECKING " +\ "THE NGAS DISK CONFIGURATION:\n" for err in notifInfo: errMsg = errMsg + "\n" + err[0] + ":\n" + err[1] + "\n" ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_ERROR, "DISK CONFIGURATION INCONSISTENCIES/" +\ "PROBLEMS ENCOUNTERED", errMsg) # Write information in the NGAS DB about the disks available. slotIds = [] for slotId in dbUpdateDic.keys(): slotIds.append(slotId) # Sort the slots such that the Main Slot is always listed before the # Replication Slot + sort the slots 'logically' according to the name. slotIdDic = {} for slotId in slotIds: storageSet = ngamsCfgObj.getStorageSetFromSlotId(slotId) slotIdDic[storageSet.getMainDiskSlotId()] = storageSet tmpSortedSlotIds = ngamsLib.logicalStrListSort(slotIdDic.keys()) sortedSlotIds = [] for slotId in tmpSortedSlotIds: slotId = slotId.strip() storageSet = slotIdDic[slotId] sortedSlotIds.append(storageSet.getMainDiskSlotId()) if (storageSet.getRepDiskSlotId() != ""): sortedSlotIds.append(storageSet.getRepDiskSlotId()) # Add or update the information for the Storage Sets in the DB for slId in sortedSlotIds: if (dbUpdateDic[slId][0] == "ADD"): addDiskInDb(hostId, dbConObj, ngamsCfgObj, slId, diskDic) else: updateDiskInDb(hostId, dbConObj, ngamsCfgObj, slId, diskDic, dbUpdateDic[slId][1]) logger.info("Archiving System: Check that there is at least one " +\ "Storage Set available for each Stream defined ...") probMimeTypeList = [] for stream in ngamsCfgObj.getStreamList(): logger.info( "Checking for target disks availability for mime-type: %s", stream.getMimeType()) if (checkStorageSetAvailability(hostId, dbConObj, ngamsCfgObj, stream.getMimeType()) != NGAMS_SUCCESS): probMimeTypeList.append(stream.getMimeType()) if ((len(probMimeTypeList) > 0) and (not ngamsCfgObj.getArchiveUnits())): errMsg = "" for mimeType in probMimeTypeList: errMsg = errMsg + " " + mimeType errMsg = genLog("NGAMS_WA_NO_TARG_DISKS", [errMsg]) logger.warning(errMsg) ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_NO_DISKS, "DISK SPACE INAVAILABILITY", errMsg)
errMsg = errMsg + " " + mimeType errMsg = genLog("NGAMS_WA_NO_TARG_DISKS", [errMsg]) logger.warning(errMsg) ngamsNotification.notify(hostId, ngamsCfgObj, NGAMS_NOTIF_NO_DISKS, "DISK SPACE INAVAILABILITY", errMsg) else: # It is not an Archiving System: Check if the disks in the Disk Dic # (the disks mounted, are registered in the DB. If yes, the info # for the disk is updated, if no, a new entry is added. logger.info("Non Archiving System: Check if the disks mounted are " +\ "registered in the DB ...") slotIds = diskDic.keys() slotIds.sort() for slotId in slotIds: diskId = diskDic[slotId].getDiskId() diskInfo = ngamsDiskInfo.ngamsDiskInfo() try: diskInfo.read(dbConObj, diskId) logger.info("Marking disk with ID: %s and mount point: %s " +\ "as mounted in the DB.", diskId, diskDic[slotId].getMountPoint()) updateDiskInDb(hostId, dbConObj, ngamsCfgObj, slotId, diskDic, diskInfo) except: logger.info("Creating new entry for disk with ID: %s " + \ "and mount point: %s in the DB.", diskId, diskDic[slotId].getMountPoint()) hasDiskInfo = 0 if (mtDiskDic.has_key(slotId)): if (mtDiskDic[slotId]): hasDiskInfo = 1 if (hasDiskInfo):