+import copy
import logging
import weakref
-def match_tags(box, all_tags, exact_tags):
- """ returns True if box has required tags """
- tall = set(all_tags)
- texact = set(exact_tags)
-
- if texact and box.connections == texact:
- return True
-
- if tall and tall.issubset(box.connections):
- return True
-
- return False
-
-def find_boxes(box, all_tags = None, exact_tags = None, max_depth = 1):
- """ Look for the connected boxes with the required tags, doing breath-first
- search, until max_depth ( max_depth = None will traverse the entire graph ).
- """
- if not all_tags and not exact_tags:
- msg = "No matching criteria for resources."
- raise RuntimeError(msg)
-
- queue = set()
- # enqueue (depth, box)
- queue.add((0, box))
-
- traversed = set()
- traversed.add(box)
-
- depth = 0
-
- result = set()
-
- while len(q) > 0:
- (depth, a) = queue.pop()
- if match_tags(a, all_tags, exact_tags):
- result.add(a)
-
- if not max_depth or depth <= max_depth:
- depth += 1
- for b in sorted(a.connections):
- if b not in traversed:
- traversed.add(b)
- queue.add((depth, b))
-
- return result
+def clsinit(cls):
+ cls._clsinit()
+ return cls
+# Decorator to invoke class initialization method
+@clsinit
class Resource(object):
- def __init__(self, box, ec):
- self._box = weakref.ref(box)
+ _rtype = "Resource"
+ _filters = None
+ _attributes = None
+
+ @classmethod
+ def _register_filter(cls, attr):
+ """ Resource subclasses will invoke this method to add a
+ filter attribute"""
+ cls._filters[attr.name] = attr
+
+ @classmethod
+ def _register_attribute(cls, attr):
+ """ Resource subclasses will invoke this method to add a
+ resource attribute"""
+ cls._attributes[attr.name] = attr
+
+ @classmethod
+ def _register_filters(cls):
+ """ Resource subclasses will invoke this method to add a
+ filter attribute"""
+ pass
+
+ @classmethod
+ def _register_attributes(cls):
+ """ Resource subclasses will invoke this method to add a
+ resource attribute"""
+ pass
+
+ @classmethod
+ def _clsinit(cls):
+ # static template for resource filters
+ cls._filters = dict()
+ cls._register_filters()
+
+ # static template for resource attributes
+ cls._attributes = dict()
+ cls._register_attributes()
+
+ @classmethod
+ def rtype(cls):
+ return cls._rtype
+
+ @classmethod
+ def get_filters(cls):
+ return copy.deepcopy(cls._filters.values())
+
+ @classmethod
+ def get_attributes(cls):
+ return copy.deepcopy(cls._attributes.values())
+
+ def __init__(self, ec, guid):
+ self._guid = guid
self._ec = weakref.ref(ec)
+ self._connections = set()
+ # the resource instance gets a copy of all attributes
+ # that can modify
+ self._attrs = copy.deepcopy(self._attributes)
# Logging
loglevel = "debug"
- self._logger = logging.getLogger("neco.execution.Resource.%s" %
- self.box.guid)
+ self._logger = logging.getLogger("neco.execution.resource.Resource.%s" %
+ self.guid)
self._logger.setLevel(getattr(logging, loglevel.upper()))
@property
- def box(self):
- return self._box()
+ def guid(self):
+ return self._guid
@property
def ec(self):
return self._ec()
- def find_resources(self, all_tags = None, exact_tags = None,
- max_depth = 1):
- resources = set()
+ def connect(self, guid):
+ if (self._validate_connection(guid)):
+ self._connections.add(guid)
+
+ def discover(self, filters):
+ pass
+
+ def provision(self, filters):
+ pass
+
+ def set(self, name, value):
+ attr = self._attrs[name]
+ attr.value = value
+
+ def get(self, name):
+ attr = self._attrs[name]
+ return attr.value
+
+ def start_after(self, time, after_status, guid):
+ pass
+
+ def stop_after(self, time, after_status, guid):
+ pass
+
+ def set_after(self, name, value, time, after_status, guid):
+ pass
+
+ def stop(self):
+ pass
+
+ def _validate_connection(self, guid):
+ # TODO: Validate!
+ return True
- boxes = find_boxes(self.box, all_tags, exact_tags, max_depth)
- for b in boxes:
- r = self.ec.resource(b.guid)
- resources.add(r)
+class ResourceFactory(object):
+ _resource_types = dict()
- return resources
+ @classmethod
+ def resource_types(cls):
+ return cls._resource_types
-class ResourceResolver(object):
- def __init__(self):
- pass
+ @classmethod
+ def register_type(cls, rclass):
+ cls._resource_types[rclass.rtype()] = rclass
+ @classmethod
+ def create(cls, rtype, ec, guid):
+ rclass = cls._resource[rtype]
+ return rclass(ec, guid)