Isolating Resource derived classes class-attributes state
[nepi.git] / src / neco / execution / resource.py
index 30294d3..80ac444 100644 (file)
+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)