blob: 310188f1c5072c7930d9e00d5d01b4aab2f4ce84 [file] [log] [blame]
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -07001# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
Ken Mixter768fe642010-04-30 17:12:04 -07002# Use of this source code is governed by a BSD-style license that can be
3# found in the LICENSE file.
4
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -07005"""Host attributes define properties on individual hosts.
6
7Host attributes are specified a strings with the format:
8 <key>{,<value>}?
9
10A machine may have a list of strings for attributes like:
11
12 ['has_80211n,True',
13 'has_ssd,False',
14 'drive_kind,string,ssd,1']
15
16A legal attribute has the pattern:
17 <name>,<kind>(,<extra>)?
18
19Name can be any legal python identifier. Kind may be any of 'string', 'True',
20or 'False'. Only if kind is string can there be extra data.
21
22Strings which are not legal attributes are ignored.
23
24Given the above list of attributes, you can use the syntax:
25 host_attributes.drive_kind => 'ssd,1'
26 host_attributes.has_80211n => True
27 host_attributes.has_ssd => False
28 host_attributes.unknown_attribute => raise KeyError
29
30Machine attributes can be specified in two ways.
31
32If you create private_host_attributes_config.py and private_host_attributes
33there, we will use it when possible instead of using the server front-end.
34
35Example configuration:
36 private_host_attributes = {
37 "mydevice": ["has_80211n,True",
38 "has_resume_bug,False"]
39 }
40
41We also consult the AFE database for its labels which are all treated as host
42attribute strings defined above. Illegal strings are ignored.
43"""
44
45
Dale Curtis7b2bd4d2011-05-02 12:39:02 -070046import hashlib, logging, os, utils
Ken Mixter768fe642010-04-30 17:12:04 -070047
Ken Mixter768fe642010-04-30 17:12:04 -070048
49private_host_attributes = utils.import_site_symbol(
50 __file__,
51 'autotest_lib.server.private_host_attributes_config',
52 'private_host_attributes', dummy={})
53
54try:
55 settings = 'autotest_lib.frontend.settings'
56 os.environ['DJANGO_SETTINGS_MODULE'] = settings
57 from autotest_lib.frontend.afe import models
58 has_models = True
Chris Sosaf4fa49b2013-01-11 17:41:57 -080059except Exception:
Ken Mixter768fe642010-04-30 17:12:04 -070060 has_models = False
61
62
63_DEFAULT_ATTRIBUTES = [
64 'has_80211n,True',
Dale Curtis3c0b6fd2011-06-13 18:38:44 -070065 'has_bluetooth,False',
Simon Glass1232f282011-02-28 09:16:28 -080066 'has_chromeos_firmware,True',
Ken Mixter768fe642010-04-30 17:12:04 -070067 'has_resume_bug,False',
Dale Curtis3c0b6fd2011-06-13 18:38:44 -070068 'has_ssd,True'
Ken Mixter768fe642010-04-30 17:12:04 -070069 ]
70
71
72class HostAttributes(object):
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -070073 """Host attribute class for site specific attributes."""
Ken Mixter768fe642010-04-30 17:12:04 -070074
75 def __init__(self, host):
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -070076 """Create an instance of HostAttribute for the given hostname.
77
78 We look up the host in both the hardcoded configuration and the AFE
79 models if they can be found.
80
81 Args:
82 host: Host name to find attributes for.
Ken Mixter768fe642010-04-30 17:12:04 -070083 """
84 self._add_attributes(_DEFAULT_ATTRIBUTES)
85 if host in private_host_attributes:
J. Richard Barnetteed460582012-08-01 16:36:40 -070086 logging.info('Including private_host_attributes file for %s', host)
Ken Mixter768fe642010-04-30 17:12:04 -070087 self._add_attributes(private_host_attributes[host])
88 if has_models:
J. Richard Barnetteed460582012-08-01 16:36:40 -070089 logging.info("Including labels for %s from database", host)
Ken Mixter768fe642010-04-30 17:12:04 -070090 host_obj = models.Host.valid_objects.get(hostname=host)
Eric Lif87edc82010-05-03 10:59:21 -070091 self._add_attributes([label.name for label in
92 host_obj.labels.all()])
Ken Mixter768fe642010-04-30 17:12:04 -070093 for key, value in self.__dict__.items():
94 logging.info('Host attribute: %s => %s', key, value)
95
Ken Mixter768fe642010-04-30 17:12:04 -070096 def _add_attributes(self, attributes):
97 for attribute in attributes:
98 splitnames = attribute.split(',')
Eric Lif87edc82010-05-03 10:59:21 -070099 if len(splitnames) == 1:
Dale Curtis7b2bd4d2011-05-02 12:39:02 -0700100 if 'netbook_' in attribute:
101 # Hash board names to prevent any accidental leaks.
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -0700102 splitnames = ['netbook_' + hashlib.sha256(
Dale Curtis7b2bd4d2011-05-02 12:39:02 -0700103 attribute.split('netbook_')[1]).hexdigest()[:8], 'True']
104 else:
J. Richard Barnetteed460582012-08-01 16:36:40 -0700105 splitnames = attribute.split(':')
106 if len(splitnames) == 2:
107 setattr(self, splitnames[0], splitnames[1])
Dale Curtis7b2bd4d2011-05-02 12:39:02 -0700108 continue
109 value = ','.join(splitnames[1:])
Ken Mixter768fe642010-04-30 17:12:04 -0700110 if value == 'True':
111 value = True
112 elif value == 'False':
113 value = False
Paul Stewartcd61a4f2010-07-19 10:49:35 -0700114 elif splitnames[1] == 'string' and len(splitnames) > 2:
115 value = ','.join(splitnames[2:])
116 else:
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -0700117 logging.info('Non-attribute string "%s" is ignored', attribute)
Ken Mixter768fe642010-04-30 17:12:04 -0700118 continue
119 setattr(self, splitnames[0], value)
Paul Pendlebury7c1fdcf2011-05-04 12:39:15 -0700120
121 def get_attributes(self):
122 """Return a list of non-False attributes for this host."""
123 return [key for key, value in self.__dict__.items() if value]