2 # -*- coding: utf-8 -*-
4 from constants import TESTBED_ID
10 # Map Node attribute to plcapi filter name
11 'hostname' : 'hostname',
15 # Map Node attribute to (<tag name>, <plcapi filter expression>)
16 # There are replacements that are applied with string formatting,
17 # so '%' has to be escaped as '%%'.
18 'architecture' : ('arch','value'),
19 'operating_system' : ('fcdistro','value'),
20 'pl_distro' : ('pldistro','value'),
21 'min_reliability' : ('reliability%(timeframe)s', ']value'),
22 'max_reliability' : ('reliability%(timeframe)s', '[value'),
23 'min_bandwidth' : ('bw%(timeframe)s', ']value'),
24 'max_bandwidth' : ('bw%(timeframe)s', '[value'),
27 def __init__(self, api=None):
34 self.architecture = None
35 self.operating_system = None
39 self.min_reliability = None
40 self.max_reliability = None
41 self.min_bandwidth = None
42 self.max_bandwidth = None
43 self.min_num_external_ifaces = None
44 self.max_num_external_ifaces = None
47 # Those are filled when an actual node is allocated
50 def build_filters(self, target_filters, filter_map):
51 for attr, tag in filter_map.iteritems():
52 value = getattr(self, attr, None)
54 target_filters[tag] = value
58 def applicable_filters(self):
59 has = lambda att : getattr(self,att,None) is not None
61 filter(has, self.BASEFILTERS.iterkeys())
62 + filter(has, self.TAGFILTERS.iterkeys())
65 def find_candidates(self):
67 replacements = {'timeframe':self.timeframe}
69 # get initial candidates (no tag filters)
70 basefilters = self.build_filters({}, self.BASEFILTERS)
72 # keyword-only "pseudofilters"
75 extra['peer'] = self.site
77 candidates = set(map(operator.itemgetter('node_id'),
78 self._api.GetNodes(filters=basefilters, fields=fields, **extra)))
80 # filter by tag, one tag at a time
81 applicable = self.applicable_filters
82 for tagfilter in self.TAGFILTERS.iteritems():
83 attr, (tagname, expr) = tagfilter
85 # don't bother if there's no filter defined
86 if attr in applicable:
87 tagfilter = basefilters.copy()
88 tagfilter['tagname'] = tagname % replacements
89 tagfilter[expr % replacements] = getattr(self,attr)
90 tagfilter['node_id'] = list(candidates)
92 candidates &= set(map(operator.itemgetter('node_id'),
93 self._api.GetNodeTags(filters=tagfilter, fields=fields)))
95 # filter by iface count
96 if self.min_num_external_ifaces is not None or self.max_num_external_ifaces is not None:
97 # fetch interfaces for all, in one go
98 filters = basefilters.copy()
99 filters['node_id'] = list(candidates)
100 ifaces = dict(map(operator.itemgetter('node_id','interface_ids'),
101 self._api.GetNodes(filters=basefilters, fields=('node_id','interface_ids')) ))
103 # filter candidates by interface count
104 if self.min_num_external_ifaces is not None and self.max_num_external_ifaces is not None:
105 predicate = ( lambda node_id :
106 self.min_num_external_ifaces <= len(ifaces.get(node_id,())) <= self.max_num_external_ifaces )
107 elif self.min_num_external_ifaces is not None:
108 predicate = ( lambda node_id :
109 self.min_num_external_ifaces <= len(ifaces.get(node_id,())) )
111 predicate = ( lambda node_id :
112 len(ifaces.get(node_id,())) <= self.max_num_external_ifaces )
114 candidates = set(filter(predicate, candidates))