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, filter_slice_id=None):
67 replacements = {'timeframe':self.timeframe}
69 # get initial candidates (no tag filters)
70 basefilters = self.build_filters({}, self.BASEFILTERS)
72 basefilters['|slice_ids'] = (filter_slice_id,)
74 # keyword-only "pseudofilters"
77 extra['peer'] = self.site
79 candidates = set(map(operator.itemgetter('node_id'),
80 self._api.GetNodes(filters=basefilters, fields=fields, **extra)))
82 # filter by tag, one tag at a time
83 applicable = self.applicable_filters
84 for tagfilter in self.TAGFILTERS.iteritems():
85 attr, (tagname, expr) = tagfilter
87 # don't bother if there's no filter defined
88 if attr in applicable:
89 tagfilter = basefilters.copy()
90 tagfilter['tagname'] = tagname % replacements
91 tagfilter[expr % replacements] = getattr(self,attr)
92 tagfilter['node_id'] = list(candidates)
94 candidates &= set(map(operator.itemgetter('node_id'),
95 self._api.GetNodeTags(filters=tagfilter, fields=fields)))
97 # filter by iface count
98 if self.min_num_external_ifaces is not None or self.max_num_external_ifaces is not None:
99 # fetch interfaces for all, in one go
100 filters = basefilters.copy()
101 filters['node_id'] = list(candidates)
102 ifaces = dict(map(operator.itemgetter('node_id','interface_ids'),
103 self._api.GetNodes(filters=basefilters, fields=('node_id','interface_ids')) ))
105 # filter candidates by interface count
106 if self.min_num_external_ifaces is not None and self.max_num_external_ifaces is not None:
107 predicate = ( lambda node_id :
108 self.min_num_external_ifaces <= len(ifaces.get(node_id,())) <= self.max_num_external_ifaces )
109 elif self.min_num_external_ifaces is not None:
110 predicate = ( lambda node_id :
111 self.min_num_external_ifaces <= len(ifaces.get(node_id,())) )
113 predicate = ( lambda node_id :
114 len(ifaces.get(node_id,())) <= self.max_num_external_ifaces )
116 candidates = set(filter(predicate, candidates))
120 def assign_node_id(self, node_id):
121 self._node_id = node_id
122 self.fetch_node_info()
124 def fetch_node_info(self):
125 info = self._api.GetNodes(self._node_id)
126 tags = dict( (t['tagname'],t['value'])
127 for t in self._api.GetNodeTags(node_id=self._node_id, fields=('tagname','value')) )
129 self.min_num_external_ifaces = None
130 self.max_num_external_ifaces = None
133 replacements = {'timeframe':self.timeframe}
134 for attr, tag in self.BASEFILTERS.iteritems():
137 setattr(self, attr, value)
138 for attr, (tag,_) in self.TAGFILTERS.iteritems():
139 tag = tag % replacements
142 setattr(self, attr, value)
144 if 'peer_id' in info:
145 self.site = self._api.peer_map[info['peer_id']]
147 if 'interface_ids' in info:
148 self.min_num_external_ifaces = \
149 self.max_num_external_ifaces = len(info['interface_ids'])