#!/usr/bin/python """ Accept commands from clients or slave systems and store a queue in a database """ # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU Library General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. # Copyright 2004 Dries Verachtert import getopt, os, sys, Queue, posix, posixpath, string from log4py import Logger sys.path.append(".") sys.path.append("pydar") sys.path.append("/usr/share/pydar2/pydar") from xmlrpclib import Server from SimpleXMLRPCServer import SimpleXMLRPCServer from config import Config from thread import start_new_thread from mastercommand import MasterCommand from storagefactory import StorageFactory from specrepositoryfactory import SpecRepositoryFactory from optparse import OptionParser import time from rights import Rights import smtplib from email.MIMEText import MIMEText from email.MIMEMultipart import MIMEMultipart from email.MIMEBase import MIMEBase from email import Encoders #os.environ['HOME'] = '/root' # This class contains the functions which get called by RPC clients # these functions must check if the caller has a valid ID: the ID should be a long unique string/pass phrase # the master accepts commands # a client program uses buildSpec to queue a build of a certain spec file for a certain distro/arch # a slave connects and calls registerSlave # the slave calls addMachRoot for each supported distro/arch # the slave calls getCommand: the master prepares a directory with a spec file to build + sources + checksums # the slave downloads that spec file + sources + checks checksums # the slave builds those rpms # the slave calls sendBuildResult to inform the master if the build succeeded or not # at a certain moment, the rpms and buildlogs are rsynced to the server # the server finds the logs & rpms and adds information about them in the database # first pydar is based on mach only: sometimes the name machRoot is still used for a distro/arch combination class MasterRpc: def __init__(self): self.__cat = Logger().get_instance(self) self.__config = Config.getInstance() self.__storage = StorageFactory.getStorage() self.__cat.debug("initialized") # a slave wants to register itself (timestamp is saved) def registerSlave(self,buildmachineId, password): self.__cat.debug("start, buildmachineId=" + buildmachineId) if self.__storage.checkIfValidBuildMachineId(buildmachineId, password, Rights.REGISTER_SLAVE): self.__storage.registerSlave(buildmachineId) return "OK" else: raise Exception("UNKNOWN BUILDMACHINEID") def sendResultFileName(self, buildmachineid, password, commandId,fileName): self.__cat.debug("buildmachineid=" + str(buildmachineid) + ",commandId=" + str(commandId) + ",fileName=" + str(fileName)) if self.__storage.checkIfValidBuildMachineId(buildmachineid, password, Rights.SEND_RESULT_FILE_NAME): self.__storage.addResultFileName(buildmachineid,commandId,fileName) return "OK" else: raise Exception( "UNKNOWN BUILDMACHINEID") def sendBuildResult(self, buildmachineid, password, commandId, buildResult): self.__cat.debug("start,buildmachineid=" + buildmachineid + ",commandId=" + str(commandId) + ",buildResult=" + str(buildResult)) if self.__storage.checkIfValidBuildMachineId(buildmachineid, password, Rights.SEND_BUILD_RESULT): self.__storage.setBuildResult(buildmachineid,commandId,buildResult) return "OK" else: raise Exception( "UNKNOWN BUILDMACHINEID") def addDistroArch(self,buildmachineId,password, distroArchTag): self.__cat.debug("start, buildmachineId=" + buildmachineId + ", distroArchTag=" + distroArchTag) if self.__storage.checkIfValidBuildMachineId(buildmachineId, password, Rights.ADD_DISTRO_ARCH): self.__storage.addDistroArchTag(buildmachineId,distroArchTag) return "OK" else: raise Exception( "UNKNOWN BUILDMACHINEID") def getCommand(self,buildmachineId, password): self.__cat.debug("start, buildmachineId=" + buildmachineId) if self.__storage.checkIfValidBuildMachineId(buildmachineId, password, Rights.GET_COMMAND): aCommand = self.__storage.reserveCommand(buildmachineId) self.__cat.debug("end, going to return a command") if (aCommand != ""): tmp = aCommand.toXmlRpcPersistantObject() self.__cat.debug("retval: " + str(tmp)) #print tmp print tmp.__dict__ return tmp else: return "" else: raise Exception( "UNKNOWN BUILDMACHINEID") def buildSpecBySpecId(self, userId, specRepoSpecFileId, toEmail, distroArchTag, priority): todo def buildSpecByPath(self, userId, password, specRepoName, specFilePath, toEmail, distroArchTag, priority, target): #self.__cat.debug("start, userId=" + userId + ",specFileName=" + specFileName + ",toEmail=" + toEmail + ",releaseTag=" + releaseTag + ",machRoot=" + machRoot + ",priority=" + priority) if self.__storage.checkIfValidUserId(userId, password, Rights.BUILD_SPEC_BY_PATH): self.__config.getCommandList().addCommand("BUILDSPECBYPATH",userId,specRepoName,specFilePath,toEmail,distroArchTag,priority,target) return "OK" else: raise Exception( "UNKNOWN USERID") def testBuildSpecByPath(self, userId,password, fileContents, toEmail, distroArchTag, priority): #self.__cat.debug("start, userId=" + userId + ",specFileName=" + specFileName + ",toEmail=" + toEmail + ",releaseTag=" + releaseTag + ",machRoot=" + machRoot + ",priority=" + priority) if self.__storage.checkIfValidUserId(userId, password, Rights.TEST_BUILD_SPEC_BY_PATH): self.__config.getCommandList().addTestCommand("TESTBUILDSPECBYPATH",userId,fileContents,toEmail,distroArchTag,priority) return "OK" else: raise Exception( "UNKNOWN USERID") def updateSpecRepositoriesFileList(self,userId,password, specRepoName): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.UPDATE_SPEC_REPOSITORIES_FILE_LIST): self.__config.getSpecRepositoryList().getSpecRepositoryByName(specRepoName).updateFileList() return "" else: raise Exception( "UNKNOWN USERID") def getNumberOfNotYetStartedCommands(self, userId, password): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.GET_NUMBER_OF_NOTYETSTARTED_COMMANDS): return self.__storage.getNumberOfNotYetStartedCommands() else: raise Exception( "UNKNOWN USERID") def updateAllSpecRepositoriesFileLists(self,userId, password): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.UPDATE_ALL_SPEC_REPOSITORIES_FILE_LISTS): retval = "" self.__config.getSpecRepositoryList().updateAllFileLists() return retval else: raise Exception( "UNKNOWN USERID") def getSpecRepositoriesUpdateCommands(self,userId, password): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.GET_SPEC_REPOSITORIES_UPDATE_COMMANDS): return self.__config.getSpecRepositoryList().getSpecRepositoriesUpdateCommands() else: raise Exception("UNKNOWN USERID") def updateTargetFileList(self, userId, password, targetName, mailTo): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.UPDATE_TARGET_FILE_LIST): target = self.__config.getTargetList().getTargetByName(targetName) if target != None: target.updateTargetFileList(userId, mailTo) else: raise Exception("target unknown") return "OK" else: raise Exception("UNKNOWN USERID") def autoQueue(self,userId, password, targetName, mailTo, priority, specRepoName, distroArchTag): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.AUTO_QUEUE): target = self.__config.getTargetList().getTargetByName(targetName) specRepo = self.__config.getSpecRepositoryList().getSpecRepositoryByName(specRepoName) if target != None and specRepo != None: target.autoQueue(mailTo, userId, priority, specRepo, distroArchTag) else: raise Exception("target or specrepo unknown") return "OK" else: raise Exception("UNKNOWN USERID") def callUpdateSiteScript(self,userId,password, specreponame): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.UPDATE_SITE_SCRIPT): tmp = self.__config.getSpecRepositoryList().getSpecRepositoryByName(specreponame) if tmp != None: tmp.runUpdateSiteScript() return "" else: raise Exception("UNKNOWN USERID") def callMoveCommandResultsScript(self,userId,password, commandId): self.__cat.debug("start,userId=" + str(userId)) if self.__storage.checkIfValidUserId(userId, password, Rights.MOVE_COMMAND_RESULTS): tmp = self.__config.getCommandList().moveCommandResults(commandId) return tmp else: raise Exception("UNKNOWN USERID") class Master: def __init__(self): self.__cat = Logger().get_instance(self) self.__config = Config.getInstance() self.__cat.debug("initialized") # update the list of known spec files self.__config.getSpecRepositoryList().updateAllFileLists() if self.__config.doCheckMissingTagsPerDistro(): self.__config.getSpecRepositoryList().addMissingSpecRepositorySpecFileTagsPerDistro() self.__cat.debug("file lists updated") def run(self): self.__cat.debug("start") self.__startListener() def __startListener(self): # open a listen socket and wait for commands from the master self.__cat.debug("buildmasterhostname=" +self.__config.getBuildMasterHostname() + ",buildmasterport=" + str(self.__config.getBuildMasterPort())) myslaveserver = SimpleXMLRPCServer((self.__config.getBuildMasterHostname(),self.__config.getBuildMasterPort())) myslaveserver.register_instance(MasterRpc()) print myslaveserver print myslaveserver.__dict__ myslaveserver.serve_forever() def main(): parser = OptionParser() parser.add_option("-m", "--masterconfig", default=None, dest="masterconfig", help="specify configuration file", metavar="FILE") (options, args) = parser.parse_args() Config.getInstance().specifyGetOptOptions(options) checkSingletons() myInstance = Master() myInstance.run() def checkSingletons(): # call getInstance once for each of the singletons, so any following call of their constructors will failed unused = Config.getInstance() unused = StorageFactory.getInstance() unused = SpecRepositoryFactory.getInstance() # code from http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66012 #if __name__ == "__main__": # if len(sys.argv) > 2 and sys.argv[1] == "-d": # # do the UNIX double-fork magic, see Stevens' "Advanced # # Programming in the UNIX Environment" for details (ISBN 0201563177) # try: # pid = os.fork() # if pid > 0: # # exit first parent ## sys.exit(0) ## except OSError, e: ## print >>sys.stderr, "fork #1 failed: %d (%s)" % (e.errno, e.strerror) ## sys.exit(1) ## ## # decouple from parent environment ## os.chdir("/") ## os.setsid() ## os.umask(0) ## ## # do second fork ## try: ## pid = os.fork() ## if pid > 0: ## # exit from second parent, print eventual PID before ## print "Daemon PID %d" % pid ## sys.exit(0) ## except OSError, e: ## print >>sys.stderr, "fork #2 failed: %d (%s)" % (e.errno, e.strerror) ## sys.exit(1) ## # start the daemon main loop ## main() ## else: ## main() main()