blob: f85e2fa6cc5178af3e0c1f70fb454d16b7e84c40 [file] [log] [blame]
#!/usr/bin/python
# Copyright 2012 Google Inc. All Rights Reserved.
#
"""Base classes for configuration objects."""
__author__ = 'Avery Pennarun (apenwarr@google.com)'
import random
class QueryError(Exception):
pass
class AttrSet(object):
"""A simple set of key-value pairs represented as a class with members."""
__slots__ = ()
def __init__(self, **kwargs):
for key in self.__slots__:
setattr(self, key, None)
self.Set(**kwargs)
def Set(self, **kwargs):
for key, value in kwargs.iteritems():
setattr(self, key, value)
def Match(self, **kwargs):
for key, value in kwargs.iteritems():
ival = getattr(self, key)
# None and False can match each other
#gpylint: disable-msg=C6403
if ival == False: ival = None
if value == False: value = None
if value == True and ival:
continue # any nonempty value is true, so match it
if ival != value:
return False
return True
def _Items(self):
for key in self.__slots__:
value = getattr(self, key)
if value == True: #gpylint: disable-msg=C6403
yield key
elif value is not None and value != False: #gpylint: disable-msg=C6403
yield '%s=%r' % (key, value)
def __repr__(self):
return '<%s>' % ','.join(self._Items())
def __str__(self):
return '\n '.join(['%s:' % self.__class__.__name__]
+ list(self._Items()))
class Host(AttrSet):
__slots__ = (
'name',
'ether',
'ip',
'ip6',
'cpu',
'platform',
'serialport',
'serialno',
'is_canary',
'is_alive',
'is_alive_net',
'is_storage',
'is_tv',
'is_nfsroot',
'has_ether',
'has_moca',
'has_wifi',
)
class Hosts(list):
"""A searchable/queryable list of Host objects."""
def FindAll(self, **kwargs):
return [i for i in self if i.Match(**kwargs)]
def _FindOne(self, **kwargs):
l = self.FindAll(**kwargs)
if l:
return l[0]
def FindOne(self, **kwargs):
v = self._FindOne(**kwargs)
if v is None:
raise KeyError(kwargs)
return v
def FindOrAdd(self, **kwargs):
h = self._FindOne(**kwargs)
if not h:
h = Host(**kwargs)
self.append(h)
if not h.name:
h.name = h.ether or h.serialno or h.ip or h.ip6
return h
def Query(self, mincount=None, maxcount=None, randomize=False, **kwargs):
"""Query the hosts list according to the given parameters.
Args:
mincount: the minimum number of hosts to return.
maxcount: the maximum number of hosts to return.
randomize: return a random subset or the first maxcount matches.
**kwargs: key=value pairs to pass to hosts.FindAll().
Returns:
A list of matching Host objects.
Raises:
QueryError: if mincount > maxcount or other invalid options.
"""
matches = self.FindAll(**kwargs)
if maxcount and maxcount < 0:
raise QueryError('max(%s) must be >= 0' % maxcount)
if maxcount and mincount > maxcount:
raise QueryError('min(%s) > max(%s)' % (mincount, maxcount))
if mincount > len(matches):
raise QueryError('not enough matches found (got=%d, wanted=%r)'
% (len(matches), mincount))
if randomize:
random.shuffle(matches)
else:
matches.sort(key=lambda i: (i.name, i.serialno, i.ether, i.ip6, i.ip))
if maxcount is not None and len(matches) > maxcount:
matches = matches[:maxcount]
return matches
def __str__(self):
return '\n'.join(str(i) for i in self)
hosts = Hosts()
def main():
print 'hello'
hosts.FindOrAdd(ether='11:22:33:44:55:66').Set(name='myhost',
ip='1.2.3.4')
print hosts
if __name__ == '__main__':
main()