• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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