machine_manager_singleton.py revision 036c9233742004aa773a374df381b1cf137484f5
1import image_chromeos 2import lock_machine 3import sys 4import threading 5import time 6from utils import command_executer 7from utils import logger 8 9 10class CrosMachine(object): 11 def __init__(self, name): 12 self.name = name 13 self.image = None 14 self.checksum = None 15 self.locked = False 16 self.released_time = time.time() 17 self.autotest_run = None 18 19 def __str__(self): 20 l = [] 21 l.append(self.name) 22 l.append(str(self.image)) 23 l.append(str(self.checksum)) 24 l.append(str(self.locked)) 25 l.append(str(self.released_time)) 26 return ", ".join(l) 27 28 29class MachineManagerSingleton(object): 30 _instance = None 31 _lock = threading.RLock() 32 _all_machines = [] 33 _machines = [] 34 image_lock = threading.Lock() 35 num_reimages = 0 36 chromeos_root = None 37 no_lock = False 38 39 def __new__(cls, *args, **kwargs): 40 with cls._lock: 41 if not cls._instance: 42 cls._instance = super(MachineManagerSingleton, cls).__new__( 43 cls, *args, **kwargs) 44 return cls._instance 45 46 def TryToLockMachine(self, cros_machine): 47 with self._lock: 48 assert cros_machine, "Machine can't be None" 49 for m in self._machines: 50 assert m.name != cros_machine.name, ( 51 "Tried to double-lock %s" % cros_machine.name) 52 if self.no_lock: 53 locked = True 54 else: 55 locked = lock_machine.Machine(cros_machine.name).Lock(True, sys.argv[0]) 56 if locked: 57 ce = command_executer.GetCommandExecuter() 58 command = "cat %s" % image_chromeos.checksum_file 59 ret, out, err = ce.CrosRunCommandWOutput( 60 command, chromeos_root=self.chromeos_root, 61 machine=cros_machine.name) 62 if ret == 0: 63 cros_machine.checksum = out.strip() 64 self._machines.append(cros_machine) 65 else: 66 logger.GetLogger().LogOutput("Warning: Couldn't lock: %s" % 67 cros_machine.name) 68 69 # This is called from single threaded mode. 70 def AddMachine(self, machine_name): 71 with self._lock: 72 for m in self._all_machines: 73 assert m.name != machine_name, "Tried to double-add %s" % machine_name 74 self._all_machines.append(CrosMachine(machine_name)) 75 76 def AcquireMachine(self, image_checksum): 77 with self._lock: 78 # Lazily external lock machines 79 if not self._machines: 80 for m in self._all_machines: 81 self.TryToLockMachine(m) 82 assert self._machines, ( 83 "Could not lock any machine in %s" % self._all_machines) 84 85### for m in self._machines: 86### if (m.locked and time.time() - m.released_time < 10 and 87### m.checksum == image_checksum): 88### return None 89 for m in [machine for machine in self._machines if not machine.locked]: 90 if m.checksum == image_checksum: 91 m.locked = True 92 m.autotest_run = threading.current_thread() 93 return m 94 for m in [machine for machine in self._machines if not machine.locked]: 95 if not m.checksum: 96 m.locked = True 97 m.autotest_run = threading.current_thread() 98 return m 99 for m in [machine for machine in self._machines if not machine.locked]: 100 if time.time() - m.released_time > 20: 101 m.locked = True 102 m.autotest_run = threading.current_thread() 103 return m 104 return None 105 106 def ReleaseMachine(self, machine): 107 with self._lock: 108 for m in self._machines: 109 if machine.name == m.name: 110 assert m.locked == True, "Tried to double-release %s" % m.name 111 m.released_time = time.time() 112 m.locked = False 113 m.status = "Available" 114 break 115 116 def __del__(self): 117 with self._lock: 118 # Unlock all machines. 119 for m in self._machines: 120 if not self.no_lock: 121 assert lock_machine.Machine(m.name).Unlock(True) == True, ( 122 "Couldn't unlock machine: %s" % m.name) 123 124 def __str__(self): 125 with self._lock: 126 l = ["MachineManager Status:"] 127 for m in self._machines: 128 l.append(str(m)) 129 return "\n".join(l) 130 131 def AsString(self): 132 with self._lock: 133 stringify_fmt = "%-30s %-10s %-4s %-25s %-32s" 134 header = stringify_fmt % ("Machine", "Thread", "Lock", "Status", "Checksum") 135 table = [header] 136 for m in self._machines: 137 if m.autotest_run: 138 autotest_name = m.autotest_run.name 139 autotest_status = m.autotest_run.status 140 else: 141 autotest_name = "" 142 autotest_status = "" 143 144 try: 145 machine_string = stringify_fmt % (m.name, 146 autotest_name, 147 m.locked, 148 autotest_status, 149 m.checksum) 150 except: 151 machine_string = "" 152 table.append(machine_string) 153 return "Machine Status:\n%s" % "\n".join(table) 154