1# Copyright 2015 The Chromium Authors. All rights reserved.
2# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
5import cStringIO
6import mimetools
7
8from common.buildbot import network
9
10
11def Slaves(master_name):
12  slave_data = network.FetchData(network.BuildUrl(master_name, 'json/slaves'))
13  return sorted(Slave(master_name, slave_name, slave_info)
14                for slave_name, slave_info in slave_data.iteritems())
15
16
17class Slave(object):
18
19  def __init__(self, master_name, name, data):
20    self._master_name = master_name
21    self._name = name
22
23    self._builders = frozenset(data['builders'].keys())
24    self._connected = data['connected']
25
26    if data['host']:
27      host_data = dict(mimetools.Message(cStringIO.StringIO(data['host'])))
28      self._bitness = 64 if '64' in host_data['architecture'] else 32
29      self._git_version = host_data['git version']
30      self._hardware = host_data['product name']
31      self._memory = float(host_data['memory total'].split()[0])
32      self._os = _ParseOs(host_data['osfamily'])
33      self._os_version = _ParseOsVersion(self._os, host_data['os version'])
34      self._processor_count = host_data['processor count']
35    else:
36      # The information is populated by Puppet. Puppet doesn't run on our GCE
37      # instances, so if the info is missing, assume it's in GCE.
38      self._bitness = 64
39      self._git_version = None
40      self._hardware = 'Compute Engine'
41      self._memory = None
42      self._os = 'linux'
43      self._os_version = None
44      self._processor_count = None
45
46  def __lt__(self, other):
47    return self.name < other.name
48
49  def __str__(self):
50    return self.name
51
52  @property
53  def master_name(self):
54    return self._master_name
55
56  @property
57  def name(self):
58    return self._name
59
60  @property
61  def builders(self):
62    return self._builders
63
64  @property
65  def bitness(self):
66    return self._bitness
67
68  @property
69  def git_version(self):
70    return self._git_version
71
72  @property
73  def hardware(self):
74    """Returns the model of the hardware.
75
76    For example, "MacBookPro11,2", "PowerEdge R220", or "Compute Engine".
77    """
78    return self._hardware
79
80  @property
81  def memory(self):
82    """Returns the quantity of RAM, in GB, as a float."""
83    return self._memory
84
85  @property
86  def os(self):
87    """Returns the canonical os name string.
88
89    The return value must be in the following list:
90    https://chromium.googlesource.com/infra/infra/+/HEAD/doc/users/services/buildbot/builders.pyl.md#os
91    """
92    return self._os
93
94  @property
95  def os_version(self):
96    """Returns the canonical major os version name string.
97
98    The return value must be in the following table:
99    https://chromium.googlesource.com/infra/infra/+/HEAD/doc/users/services/buildbot/builders.pyl.md#version
100    """
101    return self._os_version
102
103  @property
104  def processor_count(self):
105    return self._processor_count
106
107
108def _ParseOs(os_family):
109  return {
110      'darwin': 'mac',
111      'debian': 'linux',
112      'windows': 'win',
113  }[os_family.lower()]
114
115
116def _ParseOsVersion(os, os_version):
117  if os == 'mac':
118    return '.'.join(os_version.split('.')[:2])
119  elif os == 'linux':
120    return {
121        '12.04': 'precise',
122        '14.04': 'trusty',
123    }[os_version]
124  elif os == 'win':
125    return {
126        '5.1.2600': 'xp',
127        '6.0.6001': 'vista',
128        '2008 R2': '2008',  # 2008 R2
129        '7': 'win7',
130        '6.3.9600': 'win8',  # 8.1
131        '10.0.10240': 'win10',
132    }[os_version]
133  else:
134    raise ValueError('"%s" is not a valid os string.' % os)
135