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