blob: e12796eddfefbcbaceb1f2e0881a1e1738923540 [file] [log] [blame]
Ahmad Sharif4467f002012-12-20 12:09:49 -08001#!/usr/bin/python
Yunlian Jiang36f91ad2013-03-28 17:13:29 -07002
3# Copyright (c) 2013 The Chromium OS Authors. All rights reserved.
4# Use of this source code is governed by a BSD-style license that can be
5# found in the LICENSE file.
Ahmad Sharif4467f002012-12-20 12:09:49 -08006
Ahmad Shariff395c262012-10-09 17:48:09 -07007import hashlib
8import image_chromeos
9import lock_machine
10import math
11import os.path
Ahmad Sharif4467f002012-12-20 12:09:49 -080012import re
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080013import sys
14import threading
15import time
Ahmad Sharif4467f002012-12-20 12:09:49 -080016
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080017from utils import command_executer
18from utils import logger
Ahmad Shariff1d70cb2012-02-06 21:51:59 -080019from utils.file_utils import FileUtils
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080020
Ahmad Sharif4467f002012-12-20 12:09:49 -080021from image_checksummer import ImageChecksummer
22
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080023CHECKSUM_FILE = "/usr/local/osimage_checksum_file"
24
25
26class CrosMachine(object):
Ahmad Shariff395c262012-10-09 17:48:09 -070027 def __init__(self, name, chromeos_root):
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -080028 self.name = name
29 self.image = None
30 self.checksum = None
31 self.locked = False
32 self.released_time = time.time()
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -070033 self.test_run = None
Ahmad Shariff395c262012-10-09 17:48:09 -070034 self.chromeos_root = chromeos_root
Yunlian Jiange5b673f2013-05-23 11:42:53 -070035 if not self.IsReachable():
Yunlian Jiang837e07a2013-05-22 16:23:28 -070036 self.machine_checksum = None
37 return
Ahmad Shariff395c262012-10-09 17:48:09 -070038 self._GetMemoryInfo()
39 self._GetCPUInfo()
40 self._ComputeMachineChecksumString()
Ahmad Sharif4467f002012-12-20 12:09:49 -080041 self._GetMachineID()
42 self.machine_checksum = self._GetMD5Checksum(self.checksum_string)
43 self.machine_id_checksum = self._GetMD5Checksum(self.machine_id)
Ahmad Shariff395c262012-10-09 17:48:09 -070044
Yunlian Jiange5b673f2013-05-23 11:42:53 -070045 def IsReachable(self):
Yunlian Jiang837e07a2013-05-22 16:23:28 -070046 ce = command_executer.GetCommandExecuter()
47 command = "ls"
48 ret = ce.CrosRunCommand(command,
49 machine=self.name,
50 chromeos_root=self.chromeos_root)
51 if ret:
52 return False
53 return True
54
Ahmad Shariff395c262012-10-09 17:48:09 -070055 def _ParseMemoryInfo(self):
56 line = self.meminfo.splitlines()[0]
57 usable_kbytes = int(line.split()[1])
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -070058 # This code is from src/third_party/test/files/client/bin/base_utils.py
Ahmad Shariff395c262012-10-09 17:48:09 -070059 # usable_kbytes is system's usable DRAM in kbytes,
60 # as reported by memtotal() from device /proc/meminfo memtotal
61 # after Linux deducts 1.5% to 9.5% for system table overhead
62 # Undo the unknown actual deduction by rounding up
63 # to next small multiple of a big power-of-two
64 # eg 12GB - 5.1% gets rounded back up to 12GB
65 mindeduct = 0.005 # 0.5 percent
66 maxdeduct = 0.095 # 9.5 percent
67 # deduction range 1.5% .. 9.5% supports physical mem sizes
68 # 6GB .. 12GB in steps of .5GB
69 # 12GB .. 24GB in steps of 1 GB
70 # 24GB .. 48GB in steps of 2 GB ...
71 # Finer granularity in physical mem sizes would require
72 # tighter spread between min and max possible deductions
73
74 # increase mem size by at least min deduction, without rounding
75 min_kbytes = int(usable_kbytes / (1.0 - mindeduct))
76 # increase mem size further by 2**n rounding, by 0..roundKb or more
77 round_kbytes = int(usable_kbytes / (1.0 - maxdeduct)) - min_kbytes
78 # find least binary roundup 2**n that covers worst-cast roundKb
79 mod2n = 1 << int(math.ceil(math.log(round_kbytes, 2)))
80 # have round_kbytes <= mod2n < round_kbytes*2
81 # round min_kbytes up to next multiple of mod2n
82 phys_kbytes = min_kbytes + mod2n - 1
83 phys_kbytes -= phys_kbytes % mod2n # clear low bits
84 self.phys_kbytes = phys_kbytes
85
86 def _GetMemoryInfo(self):
Ahmad Sharif4467f002012-12-20 12:09:49 -080087 #TODO yunlian: when the machine in rebooting, it will not return
Ahmad Shariff395c262012-10-09 17:48:09 -070088 #meminfo, the assert does not catch it either
89 ce = command_executer.GetCommandExecuter()
90 command = "cat /proc/meminfo"
91 ret, self.meminfo, _ = ce.CrosRunCommand(
92 command, return_output=True,
93 machine=self.name, username="root", chromeos_root=self.chromeos_root)
94 assert ret == 0, "Could not get meminfo from machine: %s" % self.name
95 if ret == 0:
96 self._ParseMemoryInfo()
97
98 #cpuinfo format is different across architecture
99 #need to find a better way to parse it.
100 def _ParseCPUInfo(self,cpuinfo):
101 return 0
102
103 def _GetCPUInfo(self):
104 ce = command_executer.GetCommandExecuter()
105 command = "cat /proc/cpuinfo"
106 ret, self.cpuinfo, _ = ce.CrosRunCommand(
107 command, return_output=True,
108 machine=self.name, username="root", chromeos_root=self.chromeos_root)
109 assert ret == 0, "Could not get cpuinfo from machine: %s" % self.name
110 if ret == 0:
111 self._ParseCPUInfo(self.cpuinfo)
112
113 def _ComputeMachineChecksumString(self):
114 self.checksum_string = ""
115 exclude_lines_list = ["MHz", "BogoMIPS", "bogomips"]
116 for line in self.cpuinfo.splitlines():
117 if not any([e in line for e in exclude_lines_list]):
118 self.checksum_string += line
119 self.checksum_string += " " + str(self.phys_kbytes)
120
Ahmad Sharif4467f002012-12-20 12:09:49 -0800121 def _GetMD5Checksum(self, ss):
122 if ss:
123 return hashlib.md5(ss).hexdigest()
Ahmad Shariff395c262012-10-09 17:48:09 -0700124 else:
Ahmad Sharif4467f002012-12-20 12:09:49 -0800125 return ""
126
127 def _GetMachineID(self):
128 ce = command_executer.GetCommandExecuter()
Luis Lozanof81680c2013-03-15 14:44:13 -0700129 command = "dump_vpd_log --full --stdout"
Ahmad Sharif4467f002012-12-20 12:09:49 -0800130 ret, if_out, _ = ce.CrosRunCommand(
131 command, return_output=True,
132 machine=self.name, chromeos_root=self.chromeos_root)
133 b = if_out.splitlines()
Luis Lozanof81680c2013-03-15 14:44:13 -0700134 a = [l for l in b if "Product" in l]
Yunlian Jiang9fc99192013-05-29 16:29:51 -0700135 if len(a):
136 self.machine_id = a[0]
137 return
138 command = "ifconfig"
139 ret, if_out, _ = ce.CrosRunCommand(
140 command, return_output=True,
141 machine=self.name, chromeos_root=self.chromeos_root)
142 b = if_out.splitlines()
143 a = [l for l in b if "HWaddr" in l]
144 if len(a):
145 self.machine_id = "_".join(a)
146 return
147 assert 0, "Could not get machine_id from machine: %s" % self.name
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800148
149 def __str__(self):
150 l = []
151 l.append(self.name)
152 l.append(str(self.image))
153 l.append(str(self.checksum))
154 l.append(str(self.locked))
155 l.append(str(self.released_time))
156 return ", ".join(l)
157
158
159class MachineManager(object):
Luis Lozanof81680c2013-03-15 14:44:13 -0700160 def __init__(self, chromeos_root, acquire_timeout):
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800161 self._lock = threading.RLock()
162 self._all_machines = []
163 self._machines = []
164 self.image_lock = threading.Lock()
165 self.num_reimages = 0
166 self.chromeos_root = None
Ahmad Sharif4467f002012-12-20 12:09:49 -0800167 self.machine_checksum = {}
168 self.machine_checksum_string = {}
Luis Lozanof81680c2013-03-15 14:44:13 -0700169 self.acquire_timeout = acquire_timeout
Ahmad Sharif4467f002012-12-20 12:09:49 -0800170
171 if os.path.isdir(lock_machine.Machine.LOCKS_DIR):
Ahmad Shariff395c262012-10-09 17:48:09 -0700172 self.no_lock = False
173 else:
174 self.no_lock = True
Ahmad Sharif4467f002012-12-20 12:09:49 -0800175 self._initialized_machines = []
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800176 self.chromeos_root = chromeos_root
177
Ahmad Sharif4467f002012-12-20 12:09:49 -0800178 def ImageMachine(self, machine, label):
Luis Lozanof81680c2013-03-15 14:44:13 -0700179 checksum = ImageChecksummer().Checksum(label)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800180 if machine.checksum == checksum:
181 return
Ahmad Sharif4467f002012-12-20 12:09:49 -0800182 chromeos_root = label.chromeos_root
Ahmad Shariff1d70cb2012-02-06 21:51:59 -0800183 if not chromeos_root:
184 chromeos_root = self.chromeos_root
Ahmad Sharif4467f002012-12-20 12:09:49 -0800185 image_chromeos_args = [image_chromeos.__file__,
186 "--chromeos_root=%s" % chromeos_root,
187 "--image=%s" % label.chromeos_image,
188 "--image_args=%s" % label.image_args,
189 "--remote=%s" % machine.name]
190 if label.board:
191 image_chromeos_args.append("--board=%s" % label.board)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800192
193 # Currently can't image two machines at once.
194 # So have to serialized on this lock.
195 ce = command_executer.GetCommandExecuter()
196 with self.image_lock:
Ahmad Sharif4467f002012-12-20 12:09:49 -0800197 retval = ce.RunCommand(" ".join(["python"] + image_chromeos_args))
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800198 if retval:
Yunlian Jiang36f91ad2013-03-28 17:13:29 -0700199 cmd ="reboot && exit"
200 ce.CrosRunCommand(cmd, machine=machine.name,
201 chromeos_root=self.chromeos_root)
202 time.sleep(60)
203 retval = ce.RunCommand(" ".join(["python"] + image_chromeos_args))
204 if retval:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800205 raise Exception("Could not image machine: '%s'." % machine.name)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800206 else:
207 self.num_reimages += 1
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800208 machine.checksum = checksum
Ahmad Sharif4467f002012-12-20 12:09:49 -0800209 machine.image = label.chromeos_image
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800210
211 return retval
212
Ahmad Sharif4467f002012-12-20 12:09:49 -0800213 def ComputeCommonCheckSum(self, label):
214 for machine in self.GetMachines(label):
Ahmad Shariff395c262012-10-09 17:48:09 -0700215 if machine.machine_checksum:
Ahmad Sharif4467f002012-12-20 12:09:49 -0800216 self.machine_checksum[label.name] = machine.machine_checksum
Ahmad Shariff395c262012-10-09 17:48:09 -0700217 break
218
Ahmad Sharif4467f002012-12-20 12:09:49 -0800219 def ComputeCommonCheckSumString(self, label):
220 for machine in self.GetMachines(label):
Ahmad Shariff395c262012-10-09 17:48:09 -0700221 if machine.checksum_string:
Ahmad Sharif4467f002012-12-20 12:09:49 -0800222 self.machine_checksum_string[label.name] = machine.checksum_string
Ahmad Shariff395c262012-10-09 17:48:09 -0700223 break
224
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800225 def _TryToLockMachine(self, cros_machine):
226 with self._lock:
227 assert cros_machine, "Machine can't be None"
228 for m in self._machines:
Luis Lozanof81680c2013-03-15 14:44:13 -0700229 if m.name == cros_machine.name:
230 return
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800231 if self.no_lock:
232 locked = True
233 else:
234 locked = lock_machine.Machine(cros_machine.name).Lock(True, sys.argv[0])
235 if locked:
236 self._machines.append(cros_machine)
237 ce = command_executer.GetCommandExecuter()
238 command = "cat %s" % CHECKSUM_FILE
239 ret, out, _ = ce.CrosRunCommand(
240 command, return_output=True, chromeos_root=self.chromeos_root,
241 machine=cros_machine.name)
242 if ret == 0:
243 cros_machine.checksum = out.strip()
244 else:
245 logger.GetLogger().LogOutput("Couldn't lock: %s" % cros_machine.name)
246
247 # This is called from single threaded mode.
248 def AddMachine(self, machine_name):
249 with self._lock:
250 for m in self._all_machines:
251 assert m.name != machine_name, "Tried to double-add %s" % machine_name
Ahmad Shariff395c262012-10-09 17:48:09 -0700252 cm = CrosMachine(machine_name, self.chromeos_root)
Yunlian Jiang837e07a2013-05-22 16:23:28 -0700253 if cm.machine_checksum:
254 self._all_machines.append(cm)
Ahmad Shariff395c262012-10-09 17:48:09 -0700255
Ahmad Sharif4467f002012-12-20 12:09:49 -0800256 def AreAllMachineSame(self, label):
257 checksums = [m.machine_checksum for m in self.GetMachines(label)]
Ahmad Shariff395c262012-10-09 17:48:09 -0700258 return len(set(checksums)) == 1
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800259
Yunlian Jiange5b673f2013-05-23 11:42:53 -0700260 def RemoveMachine(self, machine_name):
261 with self._lock:
262 self._machines = [m for m in self._machines
263 if m.name != machine_name]
264 res = lock_machine.Machine(machine_name).Unlock(True)
265 if not res:
266 logger.GetLogger().LogError("Could not unlock machine: '%s'."
267 % m.name)
268
Ahmad Sharif4467f002012-12-20 12:09:49 -0800269 def AcquireMachine(self, chromeos_image, label):
Luis Lozanof81680c2013-03-15 14:44:13 -0700270 image_checksum = ImageChecksummer().Checksum(label)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800271 machines = self.GetMachines(label)
Luis Lozanof81680c2013-03-15 14:44:13 -0700272 check_interval_time = 120
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800273 with self._lock:
274 # Lazily external lock machines
Luis Lozanof81680c2013-03-15 14:44:13 -0700275 while self.acquire_timeout >= 0:
276 for m in machines:
277 new_machine = m not in self._all_machines
Ahmad Sharif4467f002012-12-20 12:09:49 -0800278 self._TryToLockMachine(m)
Luis Lozanof81680c2013-03-15 14:44:13 -0700279 if new_machine:
280 m.released_time = time.time()
281 if not self.AreAllMachineSame(label):
282 logger.GetLogger().LogFatal("-- not all the machine are identical")
283 if self.GetAvailableMachines(label):
284 break
285 else:
286 sleep_time = max(1, min(self.acquire_timeout, check_interval_time))
287 time.sleep(sleep_time)
288 self.acquire_timeout -= sleep_time
289
290 if self.acquire_timeout < 0:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800291 machine_names = []
Ahmad Sharif4467f002012-12-20 12:09:49 -0800292 for machine in machines:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800293 machine_names.append(machine.name)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800294 logger.GetLogger().LogFatal("Could not acquire any of the "
Luis Lozanof81680c2013-03-15 14:44:13 -0700295 "following machines: '%s'"
296 % ", ".join(machine_names))
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800297
298### for m in self._machines:
299### if (m.locked and time.time() - m.released_time < 10 and
300### m.checksum == image_checksum):
301### return None
Ahmad Sharif4467f002012-12-20 12:09:49 -0800302 for m in [machine for machine in self.GetAvailableMachines(label)
303 if not machine.locked]:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800304 if m.checksum == image_checksum:
305 m.locked = True
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700306 m.test_run = threading.current_thread()
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800307 return m
Ahmad Sharif4467f002012-12-20 12:09:49 -0800308 for m in [machine for machine in self.GetAvailableMachines(label)
309 if not machine.locked]:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800310 if not m.checksum:
311 m.locked = True
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700312 m.test_run = threading.current_thread()
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800313 return m
314 # This logic ensures that threads waiting on a machine will get a machine
315 # with a checksum equal to their image over other threads. This saves time
316 # when crosperf initially assigns the machines to threads by minimizing
317 # the number of re-images.
318 # TODO(asharif): If we centralize the thread-scheduler, we wont need this
319 # code and can implement minimal reimaging code more cleanly.
Ahmad Sharif4467f002012-12-20 12:09:49 -0800320 for m in [machine for machine in self.GetAvailableMachines(label)
321 if not machine.locked]:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800322 if time.time() - m.released_time > 20:
323 m.locked = True
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700324 m.test_run = threading.current_thread()
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800325 return m
326 return None
327
Ahmad Sharif4467f002012-12-20 12:09:49 -0800328 def GetAvailableMachines(self, label=None):
329 if not label:
330 return self._machines
331 return [m for m in self._machines if m.name in label.remote]
332
333 def GetMachines(self, label=None):
334 if not label:
335 return self._all_machines
336 return [m for m in self._all_machines if m.name in label.remote]
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800337
338 def ReleaseMachine(self, machine):
339 with self._lock:
340 for m in self._machines:
341 if machine.name == m.name:
342 assert m.locked == True, "Tried to double-release %s" % m.name
343 m.released_time = time.time()
344 m.locked = False
345 m.status = "Available"
346 break
347
348 def Cleanup(self):
349 with self._lock:
350 # Unlock all machines.
351 for m in self._machines:
352 if not self.no_lock:
353 res = lock_machine.Machine(m.name).Unlock(True)
354 if not res:
355 logger.GetLogger().LogError("Could not unlock machine: '%s'."
356 % m.name)
357
358 def __str__(self):
359 with self._lock:
360 l = ["MachineManager Status:"]
361 for m in self._machines:
362 l.append(str(m))
363 return "\n".join(l)
364
365 def AsString(self):
366 with self._lock:
367 stringify_fmt = "%-30s %-10s %-4s %-25s %-32s"
368 header = stringify_fmt % ("Machine", "Thread", "Lock", "Status",
369 "Checksum")
370 table = [header]
371 for m in self._machines:
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700372 if m.test_run:
373 test_name = m.test_run.name
374 test_status = m.test_run.timeline.GetLastEvent()
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800375 else:
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700376 test_name = ""
377 test_status = ""
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800378
379 try:
380 machine_string = stringify_fmt % (m.name,
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700381 test_name,
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800382 m.locked,
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700383 test_status,
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800384 m.checksum)
385 except Exception:
386 machine_string = ""
387 table.append(machine_string)
388 return "Machine Status:\n%s" % "\n".join(table)
389
Ahmad Sharif4467f002012-12-20 12:09:49 -0800390 def GetAllCPUInfo(self, labels):
391 """Get cpuinfo for labels, merge them if their cpuinfo are the same."""
392 dic = {}
393 for label in labels:
394 for machine in self._all_machines:
395 if machine.name in label.remote:
396 if machine.cpuinfo not in dic:
397 dic[machine.cpuinfo] = [label.name]
398 else:
399 dic[machine.cpuinfo].append(label.name)
400 break
401 output = ""
402 for key, v in dic.items():
403 output += " ".join(v)
404 output += "\n-------------------\n"
405 output += key
406 output += "\n\n\n"
407 return output
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800408
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800409
Ahmad Sharif4467f002012-12-20 12:09:49 -0800410class MockCrosMachine(CrosMachine):
411 def __init__(self, name, chromeos_root):
412 self.name = name
413 self.image = None
414 self.checksum = None
415 self.locked = False
416 self.released_time = time.time()
Yunlian Jiang04dc5dc2013-04-23 15:05:05 -0700417 self.test_run = None
Ahmad Sharif4467f002012-12-20 12:09:49 -0800418 self.chromeos_root = chromeos_root
419 self.checksum_string = re.sub("\d", "", name)
420 #In test, we assume "lumpy1", "lumpy2" are the same machine.
421 self.machine_checksum = self._GetMD5Checksum(self.checksum_string)
422
423
424class MockMachineManager(MachineManager):
425
Luis Lozanof81680c2013-03-15 14:44:13 -0700426 def __init__(self, chromeos_root, acquire_timeout):
427 super(MockMachineManager, self).__init__(chromeos_root, acquire_timeout)
Ahmad Sharif4467f002012-12-20 12:09:49 -0800428
429 def _TryToLockMachine(self, cros_machine):
430 self._machines.append(cros_machine)
431 cros_machine.checksum = ""
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800432
433 def AddMachine(self, machine_name):
Ahmad Sharif4467f002012-12-20 12:09:49 -0800434 with self._lock:
435 for m in self._all_machines:
436 assert m.name != machine_name, "Tried to double-add %s" % machine_name
437 cm = MockCrosMachine(machine_name, self.chromeos_root)
438 assert cm.machine_checksum, ("Could not find checksum for machine %s" %
439 machine_name)
440 self._all_machines.append(cm)
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800441
Ahmad Sharif4467f002012-12-20 12:09:49 -0800442 def AcquireMachine(self, chromeos_image, label):
443 for machine in self._all_machines:
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800444 if not machine.locked:
445 machine.locked = True
446 return machine
447 return None
448
Ahmad Sharif4467f002012-12-20 12:09:49 -0800449 def ImageMachine(self, machine_name, label):
450 return 0
451
Ahmad Sharif0dcbc4b2012-02-02 16:37:18 -0800452 def ReleaseMachine(self, machine):
453 machine.locked = False
454
Ahmad Sharif4467f002012-12-20 12:09:49 -0800455 def GetMachines(self, label):
456 return self._all_machines
457
458 def GetAvailableMachines(self, label):
459 return self._all_machines