1#!/usr/bin/python 2# 3# Copyright 2010 Google Inc. All Rights Reserved. 4 5import logging 6import optparse 7import pickle 8import signal 9from SimpleXMLRPCServer import SimpleXMLRPCServer 10import sys 11 12from automation.common import logger 13from automation.common.command_executer import CommandExecuter 14from automation.server import machine_manager 15from automation.server.job_group_manager import JobGroupManager 16from automation.server.job_manager import JobManager 17 18 19class Server(object): 20 """Plays a role of external interface accessible over XMLRPC.""" 21 22 def __init__(self, machines_file=None, dry_run=False): 23 """Default constructor. 24 25 Args: 26 machines_file: Path to file storing a list of machines. 27 dry_run: If True, the server only simulates command execution. 28 """ 29 CommandExecuter.Configure(dry_run) 30 31 self.job_manager = JobManager( 32 machine_manager.MachineManager.FromMachineListFile( 33 machines_file or machine_manager.DEFAULT_MACHINES_FILE)) 34 35 self.job_group_manager = JobGroupManager(self.job_manager) 36 37 self._logger = logging.getLogger(self.__class__.__name__) 38 39 def ExecuteJobGroup(self, job_group, dry_run=False): 40 job_group = pickle.loads(job_group) 41 self._logger.info('Received ExecuteJobGroup(%r, dry_run=%s) request.', 42 job_group, dry_run) 43 44 for job in job_group.jobs: 45 job.dry_run = dry_run 46 return self.job_group_manager.AddJobGroup(job_group) 47 48 def GetAllJobGroups(self): 49 self._logger.info('Received GetAllJobGroups() request.') 50 return pickle.dumps(self.job_group_manager.GetAllJobGroups()) 51 52 def KillJobGroup(self, job_group_id): 53 self._logger.info('Received KillJobGroup(%d) request.', job_group_id) 54 self.job_group_manager.KillJobGroup(pickle.loads(job_group_id)) 55 56 def GetJobGroup(self, job_group_id): 57 self._logger.info('Received GetJobGroup(%d) request.', job_group_id) 58 59 return pickle.dumps(self.job_group_manager.GetJobGroup(job_group_id)) 60 61 def GetJob(self, job_id): 62 self._logger.info('Received GetJob(%d) request.', job_id) 63 64 return pickle.dumps(self.job_manager.GetJob(job_id)) 65 66 def GetMachineList(self): 67 self._logger.info('Received GetMachineList() request.') 68 69 return pickle.dumps(self.job_manager.machine_manager.GetMachineList()) 70 71 def StartServer(self): 72 self.job_manager.StartJobManager() 73 74 def StopServer(self): 75 self.job_manager.StopJobManager() 76 self.job_manager.join() 77 78 79def GetServerOptions(): 80 """Get server's settings from command line options.""" 81 parser = optparse.OptionParser() 82 parser.add_option('-m', 83 '--machines-file', 84 dest='machines_file', 85 help='The location of the file ' 86 'containing the machines database', 87 default=machine_manager.DEFAULT_MACHINES_FILE) 88 parser.add_option('-n', 89 '--dry-run', 90 dest='dry_run', 91 help='Start the server in dry-run mode, where jobs will ' 92 'not actually be executed.', 93 action='store_true', 94 default=False) 95 return parser.parse_args()[0] 96 97 98def Main(): 99 logger.SetUpRootLogger(filename='server.log', level=logging.DEBUG) 100 101 options = GetServerOptions() 102 server = Server(options.machines_file, options.dry_run) 103 server.StartServer() 104 105 def _HandleKeyboardInterrupt(*_): 106 server.StopServer() 107 sys.exit(1) 108 109 signal.signal(signal.SIGINT, _HandleKeyboardInterrupt) 110 111 try: 112 xmlserver = SimpleXMLRPCServer( 113 ('localhost', 8000), 114 allow_none=True, 115 logRequests=False) 116 xmlserver.register_instance(server) 117 xmlserver.serve_forever() 118 except Exception as ex: 119 logging.error(ex) 120 server.StopServer() 121 sys.exit(1) 122 123 124if __name__ == '__main__': 125 Main() 126