class ChirpServerProcessProtocol(protocol.ProcessProtocol): logger = logging.getLogger(support.discoverCaller()) def __init__(self, aclFileName): self._aclFileName = aclFileName def connectionMade(self): self.transport.closeStdin() self.logger.debug("Process started!") def outReceived(self, data): self.logger.debug("Chirp Server stdout: %s" % data) def errReceived(self, data): self.logger.debug("Chirp Server stderr: %s" % data) def inConnectionLost(self): pass #we don't care about stdin. We do in fact close it ourselves def outConnectionLost(self): self.logger.info("Chirp Server closed its stdout") def errConnectionLost(self): self.logger.info("Chirp Server closed its stderr") def processExited(self, reason): #This is called when the child process has been reaped os.remove(self._aclFileName) def processEnded(self, reason): #This is called when all the file descriptors associated with the child #process have been closed and the process has been reaped self.logger.warn("Process ended (code: %s) " % reason.value.exitCode)
class BaseStompEngine(stomper.Engine): """ G{classtree BaseStompEngine} """ logger = logging.getLogger(support.discoverCaller()) @inject.param('msgInterpreter', MsgInterpreter, scope=inject.appscope) def __init__(self, msgInterpreter): super(BaseStompEngine, self).__init__() self._msgInterpreter = msgInterpreter def ack(self, msg): """Called when a MESSAGE message is received""" #msg is an unpacked frame self._msgInterpreter.interpret(msg) return stomper.NO_REPONSE_NEEDED def react(self, msg): """ Returns an iterable of responses """ rxdFrame = stomper.unpack_frame(msg) cmd = rxdFrame['cmd'] self.logger.info("Received a %s message." % cmd) self.logger.debug("Headers: %s ; Body: %s" % (rxdFrame['headers'], rxdFrame['body'])) try: res = list(stomper.Engine.react(self, msg)) except Exception, e: self.logger.error(str(e)) res = stomper.NO_REPONSE_NEEDED return res
def unpause(vm): def impl(): return _execProgressCmd(vm, 'unpause', None) logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread( impl ) return d
def getPerformanceData(vm): def impl(): return _perf.query(["*"], [vm]) logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
def restoreSnapshot(vm): def impl(): return _execProgressCmd(vm, 'restoreSnapshot', (name, desc)) logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
def getPerformanceData(vm): def impl(): return _perf.query( ["*"], [vm] ) logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread(impl) return d
def restoreSnapshot(vm): def impl(): return _execProgressCmd(vm, 'restoreSnapshot', (name, desc)) logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread( impl ) return d
def pause(vm): def impl(): return _execProgressCmd(vm, 'pause', None) logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
class CommandExecuter(object): logger = logging.getLogger(support.discoverCaller()) def __init__(self, cmdId, parameters): #parameters is a dict self._cmdId = cmdId self._parameters = parameters def executeCommand(self): """ Executes (or tries to) cmd. Runs cmd, returning a tuple (stdout, stderr) with the contents of the execution """ res = None cmd = self._parameters.pop('cmd') fileForStdin = self._parameters.pop('fileForStdin') try: if fileForStdin: fileForStdin = file(fileForStdin, 'r') except Exception, e: res = defer.fail(('', str(e), -1)) #mimic process output self._execResUsage = resource.getrusage(resource.RUSAGE_CHILDREN) else:
class VMStompEngine(BaseStompEngine): """ This basically models a client (ie, VM instance)""" logger = logging.getLogger(support.discoverCaller()) config = inject.attr("config") words = inject.attr("words") stompProtocol = inject.attr('stompProtocol', scope=inject.appscope) def __init__(self): super( VMStompEngine, self).__init__() networkInterface = self.config.get('VM', 'network_interface') networkInterfaceData = netifaces.ifaddresses(networkInterface) self._id, self._ip = [ networkInterfaceData[af][0]['addr'] for af in (netifaces.AF_LINK, netifaces.AF_INET) ] self._id = self._id.upper() self.logger.debug("VM instantiated with id/ip %s/%s" % (self._id, self._ip) ) self._descriptor = EntityDescriptor(self._id, ip=self._ip) @property def descriptor(self): return self._descriptor def connected(self, msg): res = [] #once connected, subscribe res.append(stomper.subscribe(destinations.CMD_REQ_DESTINATION)) #announce ourselves res.append( self.words['HELLO']().howToSay() ) return tuple(res) def pong(self, pingMsg): self.stompProtocol.sendMsg( self.words['PONG']().howToSay(pingMsg) ) def dealWithExecutionResults(self, results): resultsFields = ('cmd-id', 'out', 'err', 'finished', 'exitCodeOrSignal', 'resources' ) #see CommandExecuter.getExecutionResults resultsDict = dict( zip( resultsFields, results ) ) #self.protocol got injected by StompProtocol self.stompProtocol.sendMsg( self.words['CMD_RESULT']().howToSay(resultsDict) ) @property def id(self): return self._id @property def ip(self): return self._ip def __repr__(self): return "VM with ID/IP: %s/%s" % (self.id, self.ip)
def listAvailableVMs(): def impl(): vbox = _ctx['vbox'] ms = _getMachines() msNames = [ str(m.name) for m in ms ] return msNames logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread(impl) return d
def listAvailableVMs(): def impl(): vbox = _ctx['vbox'] ms = _getMachines() msNames = [str(m.name) for m in ms] return msNames logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
def listVMsWithState(): def impl(): vbox = _ctx['vbox'] ms = _getMachines() msNamesAndStates = [ (str(m.name), _getNameForMachineStateCode(m.state)) \ for m in ms ] return dict(msNamesAndStates) logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread(impl) return d
class HostStompEngine(BaseStompEngine): logger = logging.getLogger(support.discoverCaller()) def __init__(self): super(HostStompEngine, self).__init__() def connected(self, msg): #once connected, subscribe return (stomper.subscribe(destinations.CONN_DESTINATION), stomper.subscribe(destinations.CMD_RES_DESTINATION))
def getState( vm): def impl(): m = _ctx['vbox'].findMachine(vm) stateCode = m.state stateName = _getNameForMachineStateCode(stateCode) return stateName logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread(impl) return d
def getState(vm): def impl(): m = _ctx['vbox'].findMachine(vm) stateCode = m.state stateName = _getNameForMachineStateCode(stateCode) return stateName logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
def listVMsWithState(): def impl(): vbox = _ctx['vbox'] ms = _getMachines() msNamesAndStates = [ (str(m.name), _getNameForMachineStateCode(m.state)) \ for m in ms ] return dict(msNamesAndStates) logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
def createVM(name, hddImagePath): vbox = _ctx['vbox'] mgr = _ctx['mgr'] def impl(): ms = _getMachines() for m in ms: if m.name == name: raise ValueError("VM '%s' already exists" % name) guestType = vbox.getGuestOSType('Linux26') newMachine = vbox.createMachine( name, guestType.id, "", "00000000-0000-0000-0000-000000000000", False) if not os.path.isfile(hddImagePath): raise IOError("HDD image path doesn't point to a valid file: %s" % hddImagePath) try: newMachine.saveSettings() #register the machine with VB (ie, make it visible) vbox.registerMachine(newMachine) session = mgr.getSessionObject(vbox) vbox.openSession(session, newMachine.id) mutableM = session.machine _attachNICs(mutableM) _addSCSIStorageController(mutableM) _attachHDToMachine(mutableM, hddImagePath) except: if session.state == _ctx['ifaces'].SessionState_Open: session.close() m = vbox.unregisterMachine(newMachine.id) m.deleteSettings() msg = "Rolled back creation of VM '%s'" % m.name logger.debug(msg) #the following two lines should go in a finally:, #but that's not supported by python 2.4 if session.state == _ctx['ifaces'].SessionState_Open: session.close() raise #the following two lines should go in a finally:, #but that's not supported by python 2.4 if session.state == _ctx['ifaces'].SessionState_Open: session.close() return (True, name) logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
def listRunningVMs(): def impl(): vbox = _ctx['vbox'] ms = _getMachines() isRunning = lambda m: m.state == _ctx['ifaces'].MachineState_Running res = filter( isRunning, ms ) res = [ str(m.name) for m in res ] return res logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread(impl) return d
def listRunningVMs(): def impl(): vbox = _ctx['vbox'] ms = _getMachines() isRunning = lambda m: m.state == _ctx['ifaces'].MachineState_Running res = filter(isRunning, ms) res = [str(m.name) for m in res] return res logger.debug("Controller method %s invoked" % support.discoverCaller()) d = threads.deferToThread(impl) return d
class FileTxs(object): """ Handles the file transmission (to and from). """ logger = logging.getLogger(support.discoverCaller()) vmRegistry = inject.attr('VMRegistry', VMRegistry) def __init__(self): pass def cpFileToVM(self, vmId, pathToLocalFileName, pathToRemoteFileName=None): """ @param pathToRemoteFileName where to store the file, relative to the root of the server. If None, the basename of the source will be stored in the / of the server. """ #this returns a deferred whose callbacks take care of returning the result if not self.vmRegistry.isValid(vmId): msg = "Invalid VM Id: '%s'" % vmId self.logger.error(msg) dres = defer.fail(msg) else: vmIp = self.vmRegistry[vmId].ip if not pathToRemoteFileName: pathToRemoteFileName = basename(pathToLocalFileName) #chirp_put [options] <local-file> <hostname[:port]> <remote-file> args = ('-t 10', pathToLocalFileName, vmIp, pathToRemoteFileName ) #FIXME: magic numbers chirp_cmd = join(self._chirpPath, 'chirp_put') dres = utils.getProcessOutputAndValue(chirp_cmd, args) return dres def cpFileFromVM(self, vmId, pathToRemoteFileName, pathToLocalFileName=None): #this returns a deferred whose callbacks take care of returning the result if not self.vmRegistry.isValid(vmId): msg = "Invalid VM Id: '%s'" % vmId self.logger.error(msg) dres = defer.fail(msg) else: vmIp = self._vms[vmId].ip if not pathToLocalFileName: pathToLocalFileName = pathToRemoteFileName #chirp_get [options] <hostname[:port]> <remote-file> <local-file> args = ('-t 10', vmIp, pathToRemoteFileName, pathToLocalFileName ) #FIXME: magic numbers chirp_cmd = join(self._chirpPath, 'chirp_get') dres = utils.getProcessOutputAndValue(chirp_cmd, args) return dres
def createVM(name, hddImagePath): vbox = _ctx['vbox'] mgr = _ctx['mgr'] def impl(): ms = _getMachines() for m in ms: if m.name == name: raise ValueError("VM '%s' already exists" % name) guestType = vbox.getGuestOSType('Linux26') newMachine = vbox.createMachine(name, guestType.id, "", "00000000-0000-0000-0000-000000000000", False) if not os.path.isfile( hddImagePath ): raise IOError("HDD image path doesn't point to a valid file: %s" % hddImagePath ) try: newMachine.saveSettings() #register the machine with VB (ie, make it visible) vbox.registerMachine( newMachine ) session = mgr.getSessionObject(vbox) vbox.openSession( session, newMachine.id ) mutableM = session.machine _attachNICs( mutableM ) _addSCSIStorageController( mutableM ) _attachHDToMachine( mutableM, hddImagePath ) except: if session.state == _ctx['ifaces'].SessionState_Open : session.close() m = vbox.unregisterMachine(newMachine.id) m.deleteSettings() msg = "Rolled back creation of VM '%s'" % m.name logger.debug(msg) #the following two lines should go in a finally:, #but that's not supported by python 2.4 if session.state == _ctx['ifaces'].SessionState_Open: session.close() raise #the following two lines should go in a finally:, #but that's not supported by python 2.4 if session.state == _ctx['ifaces'].SessionState_Open: session.close() return (True, name) logger.debug("Controller method %s invoked" % support.discoverCaller() ) d = threads.deferToThread( impl ) return d
def start(vm): #what an ugly hack this is... if platform.system() != "Windows": def impl(): session = _ctx['mgr'].getSessionObject(_ctx['vbox']) mach = _findMachineByNameOrId(vm) logger.info("Starting VM for machine %s" % mach.name) progress = _ctx['vbox'].openRemoteSession(session, mach.id, "vrdp", "") progress.waitForCompletion(WAITING_GRACE_MS) completed = progress.completed if completed and (progress.resultCode == 0): logger.info("Startup of machine %s completed: %s" % (mach.name, str(completed))) else: _reportError(progress) return False session.close() return True d = threads.deferToThread(impl) else: m = _findMachineByNameOrId(vm) mName = str(m.name) processProtocol = VBoxHeadlessProcessProtocol() pseudoCWD = os.path.dirname(sys.modules[__name__].__file__) vboxBinariesPath = None #TODO: use VBOX_INSTALL_PATH cmdWithPath = os.path.join(pseudoCWD, 'scripts', 'vboxstart.bat') cmdWithArgs = ("vboxstart.bat", vboxBinariesPath, mName) cmdPath = os.path.join(pseudoCWD, 'scripts') newProc = lambda: reactor.spawnProcess(processProtocol, cmdWithPath, args=cmdWithArgs, env=None, path=cmdPath) reactor.callWhenRunning(newProc) d = True #in order to have a unique return try: _startCollectingPerfData(vm) except: pass #TODO: loggging logger.debug("Controller method %s invoked" % support.discoverCaller()) return d
class CommandRegistry(object): """ For all command-execution related. Keeps track of requests made, served and retired """ logger = logging.getLogger(support.discoverCaller()) words = inject.attr('words') vmRegistry = inject.attr('vmRegistry', VMRegistry) def __init__(self): self._cmdReqsSent = { } #cmdId: dict with keys (timestamp, to, cmd, args, env, path) self._cmdReqsRetired = {} #finished cmdReqsSent self._cmdReqsRcvd = {} def addCmdRequest(self, cmdId, requestInfoDict): self._cmdReqsSent[cmdId] = requestInfoDict def processCmdResult(self, resultsMsg): serializedResults = resultsMsg['body'].split(None, 1)[1] #serializeded data: dict with keys (cmd-id, out, err, finished?, code/signal, resources) results = support.deserialize(serializedResults) self.logger.debug("Deserialized results: %s" % results) cmdId = results.pop('cmd-id') #this comes from a word.CMD_RESULT.listenAndAct #note down for which cmd we are getting the result back assert cmdId in self._cmdReqsSent self._cmdReqsRcvd[cmdId] = results self._cmdReqsRetired[cmdId] = self._cmdReqsSent.pop(cmdId) self.logger.info("Received command results for cmd-id '%s'", cmdId) def popCmdResults(self, cmdId): # for invalid cmdIds, returning None could # result in problems with xml-rpc. Thus we # resource to an empty string, which likewise # fails a boolean test return self._cmdReqsRcvd.pop(cmdId, "") def listFinishedCmds(self): return self._cmdReqsRcvd.keys() def getCmdDetails(self, cmdId): details = self._cmdReqsSent.get(cmdId) if not details: details = self._cmdReqsRetired.get(cmdId) return support.serialize(details)
def start(vm): #what an ugly hack this is... if platform.system() != "Windows": def impl(): session = _ctx['mgr'].getSessionObject(_ctx['vbox']) mach = _findMachineByNameOrId(vm) logger.info("Starting VM for machine %s" % mach.name) progress = _ctx['vbox'].openRemoteSession(session, mach.id, "vrdp", "") progress.waitForCompletion(WAITING_GRACE_MS) completed = progress.completed if completed and (progress.resultCode == 0): logger.info("Startup of machine %s completed: %s" % (mach.name, str(completed))) else: _reportError(progress) return False session.close() return True d = threads.deferToThread(impl) else: m = _findMachineByNameOrId(vm) mName = str(m.name) processProtocol = VBoxHeadlessProcessProtocol() pseudoCWD = os.path.dirname(sys.modules[__name__].__file__) vboxBinariesPath = None #TODO: use VBOX_INSTALL_PATH cmdWithPath = os.path.join(pseudoCWD, 'scripts', 'vboxstart.bat') cmdWithArgs = ("vboxstart.bat", vboxBinariesPath, mName) cmdPath = os.path.join(pseudoCWD, 'scripts') newProc = lambda: reactor.spawnProcess( processProtocol, cmdWithPath, args=cmdWithArgs, env=None, path=cmdPath ) reactor.callWhenRunning(newProc) d = True #in order to have a unique return try: _startCollectingPerfData(vm) except: pass #TODO: loggging logger.debug("Controller method %s invoked" % support.discoverCaller() ) return d
class StompProtocol(Protocol): #transport available at self.transport, as set by BaseProtocol.makeConnection #factory available at self.factory, as set by Factory.buildProtocol logger = logging.getLogger(support.discoverCaller()) stompEngine = inject.attr('stompEngine') config = inject.attr('config') def __init__(self): self._username = self.config.get('Broker', 'username') self._password = self.config.get('Broker', 'password') def sendMsg(self, msg): self.logger.debug("Sending msg '%s'" % msg) self.transport.write(msg) def connectionMade(self): """ Called when a connection is made. Protocol initialization happens here """ self.logger.info("Connection with the broker made") stompConnectMsg = stomper.connect(self._username, self._password) self.sendMsg(stompConnectMsg) try: self.factory.resetDelay() except: pass def connectionLost(self, reason): """Called when the connection is shut down""" self.logger.info("Connection with the broker lost") def dataReceived(self, data): """Called whenever data is received""" reactions = self.stompEngine.react(data) if reactions: for reaction in filter(None, reactions): self.sendMsg(reaction)
class StompProtocolFactory(ReconnectingClientFactory): """ Responsible for creating an instance of L{StompProtocol} """ logger = logging.getLogger(support.discoverCaller()) __stompProtocol = inject.attr('stompProtocol') initialDelay = delay = 5.0 factor = 1.0 jitter = 0.0 def __init__(self): #retry every 5 seconds, with no back-off self.protocol = lambda: self.__stompProtocol #sigh... self.protocol must be callable def clientConnectionLost(self, connector, reason): self.logger.info("Connection with the broker lost: %s" % reason) ReconnectingClientFactory.clientConnectionLost(self, connector, reason) def clientConnectionFailed(self, connector, reason): self.logger.error("Connection with the broker failed: %s" % reason) ReconnectingClientFactory.clientConnectionFailed( self, connector, reason)
class MsgInterpreter(object): logger = logging.getLogger(support.discoverCaller()) @inject.param('words') def __init__(self, words): """ @param words a list of "words" (ie, commands represented as classes) """ self._words = words def interpret(self, msg): #msg is an unpacked STOMP frame firstWord = msg['body'].split(None, 1)[0] #only interested in the 1st word self.logger.debug("Trying to interpret %s" % (firstWord, )) try: word = self._words[firstWord]() except KeyError: raise NameError("Word '%s' unknown" % firstWord) word.listenAndAct(msg)
import CommandExecuter from boincvm.common import support import logging import time import stomper import fnmatch logger = logging.getLogger(support.discoverCaller()) CMD_REQ_DESTINATION = "/topic/cmd_requests" CMD_RES_DESTINATION = "/topic/cmd_responses" CONN_DESTINATION = "/topic/connections" class BaseWord(object): """ Initializes the Frame object with the inheriting class' name """ def __init__(self, src, dst): """ @param invoker instance of the element (host, vm) receiving/sending the word. """ self._frame = stomper.Frame() self._frame.body = self.__name__ headers = {} headers['from'] = src headers['to'] = dst headers['timestamp'] = str(time.time()) self._frame.headers = headers self._frame.cmd = 'SEND'
from boincvm.common import support import logging import time import stomper import inject import pdb logger = logging.getLogger(support.discoverCaller()) class BaseWord(object): """ Initializes the Frame object with the inheriting class' name """ @inject.param("subject") def __init__(self, subject): self.subject = subject self.frame = stomper.Frame() self.frame.cmd = "SEND" self.frame.body = self.name headers = {} headers["from"] = subject.descriptor.id headers["timestamp"] = str(time.time()) self.frame.headers = headers @property def name(self): """ Get the word's name """ return self.__class__.__name__
class VMRegistry(object): """ Keeps track of the registered virtual machines. """ logger = logging.getLogger(support.discoverCaller()) #PING/PONG #HELLO/BYE #STILL_ALIVE @inject.param('hvController') def __init__(self, hvController): self._vms = {} self._hvController = hvController self._idsToNames = self._getIdsToNamesMapping() self._namesToIds = dict( (v, k) for k, v in self._idsToNames.iteritems()) def addVM(self, vmDescriptor): """ @param vmDescriptor an instance of L{EntityDescriptor} """ name = self.getNameForId(vmDescriptor.id) vmDescriptor.name = name self._vms[vmDescriptor.id] = vmDescriptor self.logger.info("VM '%s' has joined the party" % self._vms[vmDescriptor.id].name) def removeVM(self, vmId): """ Removes a VM from the party """ vmDescriptor = self._vms.pop(vmId) self.logger.info("VM '%s' has left the party" % vmDescriptor.name) def isValid(self, vmId): return vmId in self._vms def __getitem__(self, vmId): return self._vms[vmId] def getRegisteredVMs(self): """ Returns a list of the registered VMs """ return self._vms.keys() def getNameForId(self, vmId): name = self._idsToNames.get(vmId) if not name: self.logger.error( "Unable to match VM ID '%s' to any registered VM (is \ the VM controller really running from within a VM?)", str(vmId)) raise Exceptions.NoSuchVirtualMachine(str(vmId)) else: return name def getIdForName(self, vmName): id_ = self._namesToIds.get(vmName) if not id_: self.logger.error( "Unable to match VM name '%s' to any registered VM (is \ the VM controller really running from within a VM?)", vmName) raise Exceptions.NoSuchVirtualMachine(vmName) else: return id_ def _getIdsToNamesMapping(self): def holder(): pass holder.res = None @defer.inlineCallbacks def _initializeIdsToNamesMapping(): idsToNamesMap = yield self._hvController.getIdsToNamesMapping() self.logger.debug("Ids -> Names table initialized: %s" % idsToNamesMap) holder.res = idsToNamesMap _initializeIdsToNamesMapping() return holder.res
class HostXMLRPCService(xmlrpc.XMLRPC, object): logger = logging.getLogger(support.discoverCaller()) @inject.param('config') @inject.param('hvController') @inject.param('subject') def __init__(self, config, hvController, subject): xmlrpc.XMLRPC.__init__(self) self._config = config self._hvController = hvController self._createHVControllerMethods() self._host = subject #from xmlrpc.XMLRPC def _getFunction(self, functionPath): f = super(HostXMLRPCService, self)._getFunction(functionPath) # f is an xmlrpc_ method def wrapWithCallbacks(*args, **kw): return defer.maybeDeferred(f, *args, **kw).addCallbacks(_success, _fail) return wrapWithCallbacks def makeEngineAccesible(self): siteRoot = resource.Resource() siteRoot.putChild('RPC2', self) port = int(self._config.get('Host', 'xmlrpc_port')) listen_on = self._config.get('Host', 'xmlrpc_listen_on') reactor.listenTCP(port, server.Site(siteRoot), interface=listen_on) ########################### ## Operation on the VMs ## ########################### def xmlrpc_listRegisteredVMs(self): registeredVMIds = self._host.getRegisteredVMs() return map(self._getNameForId, registeredVMIds) def xmlrpc_runCmd(self, toVmName, cmd, args=(), env={}, path=None, fileForStdin=''): cmdId = self._host.sendCmdRequest(toVmName, cmd, args, env, path, fileForStdin) return cmdId def xmlrpc_ping(self, toVmName, timeout_secs=5.0): #FIXME: magic number of seconds vmId = self._getIdForName(toVmName) return self._host.ping(vmId, timeout_secs) def xmlrpc_listFinishedCmds(self): return self._host.listFinishedCmds() def xmlrpc_getCmdResults(self, cmdId): return self._host.getCmdResults(cmdId) def xmlrpc_getCmdDetails(self, cmdId): return self._host.getCmdDetails(cmdId) def xmlrpc_cpFileToVM(self, vmName, pathToLocalFileName, pathToRemoteFileName=None): vmId = self._getIdForName(vmName) return self._host.cpFileToVM(vmId, pathToLocalFileName, pathToRemoteFileName) def xmlrpc_cpFileFromVM(self, vmName, pathToRemoteFileName, pathToLocalFileName=None): vmId = self._getIdForName(vmName) return self._host.cpFileFromVM(vmId, pathToRemoteFileName, pathToLocalFileName) ################################################ ## Hypervisor controller dependent operations ## ################################################ def _inspectHVControllerMethods(self): allMethods = inspect.getmembers(self._hvController, inspect.isfunction) publicMethods = filter(lambda method: method[0][0] != '_', allMethods) return publicMethods def _addMethod(self, method): name = 'xmlrpc_' + method.func_name setattr(self, name, method) def _createHVControllerMethods(self): self.hvControllerMethods = self._inspectHVControllerMethods() for method in self.hvControllerMethods: self._addMethod(method[1]) self.logger.debug("Controler method %s dynamically added" % method[0]) def xmlrpc_help(self, methodName=None): if not methodName: allMethods = inspect.getmembers(self) xmlrpcMethods = filter( lambda method: method[0].startswith('xmlrpc_'), allMethods) methodNames = map(lambda m: m[0][len('xmlrpc_'):], xmlrpcMethods) resList = map(lambda mName: "%s" % self.xmlrpc_help(mName), methodNames) res = '\n\n'.join(resList) else: f = getattr(self, 'xmlrpc_' + methodName, None) if not f: raise ValueError('No such method: %s' % methodName) else: signature = _getPrintableFunctionSignature(f) res = '%s%s:\n%s' % ( methodName, signature, f.__doc__ or '<No Docstring>', ) return res
class Host(object): logger = logging.getLogger(support.discoverCaller()) #we use injection so that we can do things lazily cmdRegistry = inject.attr('cmdRegistry', CommandRegistry) vmRegistry = inject.attr('vmRegistry', VMRegistry) fileTxs = inject.attr('fileTxs', FileTxs) words = inject.attr('words') stompProtocol = inject.attr('stompProtocol') def __init__(self): self._descriptor = EntityDescriptor('Host-ID') @property def descriptor(self): return self._descriptor def sendCmdRequest(self, toVmName, cmd, args=(), env={}, path=None, fileForStdin=''): #get id for name toVmId = self.vmRegistry.getIdForName(toVmName) cmdId = str(uuid.uuid4()) toSend = self.words['CMD_RUN'](). \ howToSay(toVmId, \ cmdId, cmd, args, \ env, path, fileForStdin ) requestKeys = ('timestamp', 'toVmName', 'toVmId', 'cmd', 'args', 'env', 'path', 'fileForStdin') requestValues = (time.time(), toVmName, toVmId, cmd, args, env, path, fileForStdin) self.stompProtocol.sendMsg(toSend) self.logger.info( "Requested execution of command '%s' with cmd-id '%s'" % (cmd, cmdId)) self.cmdRegistry.addCmdRequest(cmdId, dict(zip(requestKeys, requestValues))) return cmdId def processCmdResult(self, resultsMsg): self.cmdRegistry.processCmdResult(resultsMsg) #XXX: make it possible to be blocking? def getCmdResults(self, cmdId): return self.cmdRegistry.popCmdResults(cmdId) ################################ def addVM(self, vmDescriptor): self.vmRegistry.addVM(vmDescriptor) def removeVM(): self.vmRegistry.removeVM(vmId) ################################ def cpFileToVM(self, vmId, pathToLocalFileName, pathToRemoteFileName=None): self.fileTxs.cpFileToVM(vmId, pathToLocalFileName, pathToRemoteFileName) def cpFileFromVM(self, vmId, pathToRemoteFileName, pathToLocalFileName=None): self.fileTxs.cpFileFromVM(vmId, pathToRemoteFileName, pathToLocalFileName)