1# Copyright 2010 Google Inc. All Rights Reserved. 2 3__author__ = 'asharif@google.com (Ahmad Sharif)' 4 5from operator import attrgetter 6import copy 7import csv 8import threading 9import os.path 10 11from automation.common import machine 12 13DEFAULT_MACHINES_FILE = os.path.join(os.path.dirname(__file__), 'test_pool.csv') 14 15 16class MachineManager(object): 17 """Container for list of machines one can run jobs on.""" 18 19 @classmethod 20 def FromMachineListFile(cls, filename): 21 # Read the file and skip header 22 csv_file = csv.reader(open(filename, 'rb'), delimiter=',', quotechar='"') 23 csv_file.next() 24 25 return cls([machine.Machine(hostname, label, cpu, int(cores), os, user) 26 for hostname, label, cpu, cores, os, user in csv_file]) 27 28 def __init__(self, machines): 29 self._machine_pool = machines 30 self._lock = threading.RLock() 31 32 def _GetMachine(self, mach_spec): 33 available_pool = [m for m in self._machine_pool if mach_spec.IsMatch(m)] 34 35 if available_pool: 36 # find a machine with minimum uses 37 uses = attrgetter('uses') 38 39 mach = min(available_pool, key=uses) 40 41 if mach_spec.preferred_machines: 42 preferred_pool = [m 43 for m in available_pool 44 if m.hostname in mach_spec.preferred_machines] 45 if preferred_pool: 46 mach = min(preferred_pool, key=uses) 47 48 mach.Acquire(mach_spec.lock_required) 49 50 return mach 51 52 def GetMachines(self, required_machines): 53 """Acquire machines for use by a job.""" 54 55 with self._lock: 56 acquired_machines = [self._GetMachine(ms) for ms in required_machines] 57 58 if not all(acquired_machines): 59 # Roll back acquires 60 while acquired_machines: 61 mach = acquired_machines.pop() 62 if mach: 63 mach.Release() 64 65 return acquired_machines 66 67 def GetMachineList(self): 68 with self._lock: 69 return copy.deepcopy(self._machine_pool) 70 71 def ReturnMachines(self, machines): 72 with self._lock: 73 for m in machines: 74 m.Release() 75 76 def __str__(self): 77 return str(self._machine_pool) 78