# Copyright 2010 Google Inc. All Rights Reserved. __author__ = 'asharif@google.com (Ahmad Sharif)' from operator import attrgetter import copy import csv import threading import os.path from automation.common import machine DEFAULT_MACHINES_FILE = os.path.join(os.path.dirname(__file__), 'test_pool.csv') class MachineManager(object): """Container for list of machines one can run jobs on.""" @classmethod def FromMachineListFile(cls, filename): # Read the file and skip header csv_file = csv.reader(open(filename, 'rb'), delimiter=',', quotechar='"') csv_file.next() return cls([machine.Machine(hostname, label, cpu, int(cores), os, user) for hostname, label, cpu, cores, os, user in csv_file]) def __init__(self, machines): self._machine_pool = machines self._lock = threading.RLock() def _GetMachine(self, mach_spec): available_pool = [m for m in self._machine_pool if mach_spec.IsMatch(m)] if available_pool: # find a machine with minimum uses uses = attrgetter('uses') mach = min(available_pool, key=uses) if mach_spec.preferred_machines: preferred_pool = [m for m in available_pool if m.hostname in mach_spec.preferred_machines] if preferred_pool: mach = min(preferred_pool, key=uses) mach.Acquire(mach_spec.lock_required) return mach def GetMachines(self, required_machines): """Acquire machines for use by a job.""" with self._lock: acquired_machines = [self._GetMachine(ms) for ms in required_machines] if not all(acquired_machines): # Roll back acquires while acquired_machines: mach = acquired_machines.pop() if mach: mach.Release() return acquired_machines def GetMachineList(self): with self._lock: return copy.deepcopy(self._machine_pool) def ReturnMachines(self, machines): with self._lock: for m in machines: m.Release() def __str__(self): return str(self._machine_pool)