Martin Sivák has uploaded a new change for review.

Change subject: Add support for optional collector fields and (valid expr) test
......................................................................

Add support for optional collector fields and (valid expr) test

This adds support for fields that might or might not be
collected. When that happens the data fields are set to None.

The policy can then use (valid expression) to test whether
expression evaluates to non-None value.

Change-Id: I3a93f0985870b431c315918b14fee6629eac70fb
Signed-off-by: Martin Sivak <[email protected]>
---
M mom/Collectors/Collector.py
M mom/Monitor.py
M mom/Policy/Parser.py
M tests/ParserTests.py
4 files changed, 48 insertions(+), 5 deletions(-)


  git pull ssh://gerrit.ovirt.org:29418/mom refs/changes/50/21050/1

diff --git a/mom/Collectors/Collector.py b/mom/Collectors/Collector.py
index 76a9cc8..da5cbbc 100644
--- a/mom/Collectors/Collector.py
+++ b/mom/Collectors/Collector.py
@@ -49,6 +49,14 @@
         """
         return set()
 
+    def getOptionalFields(self=None):
+        """
+        Used to query the names of statistics that this Collector will return
+        Override this method when creating new collectors.
+        Return: A set containing the names of all statistics returned by 
collect()
+        """
+        return set()
+
 def get_collectors(config_str, properties, global_config):
     """
     Initialize a set of new Collector instances for a Monitor.
diff --git a/mom/Monitor.py b/mom/Monitor.py
index 8daccec..ee555f8 100644
--- a/mom/Monitor.py
+++ b/mom/Monitor.py
@@ -37,6 +37,7 @@
         self.variables = {}
         self.name = name
         self.fields = None
+        self.optional_fields = None
         self.collectors = []
         self.logger = logging.getLogger('mom.Monitor')
 
@@ -68,14 +69,27 @@
             for c in self.collectors:
                 self.fields |= c.getFields()
             self.logger.debug("Using fields: %s", repr(self.fields))
-            if self.plotter is not None:
-                self.plotter.setFields(self.fields)
+
+        # The first time we are called, populate the list of optional fields
+        if self.optional_fields is None:
+            self.optional_fields = set()
+            for c in self.collectors:
+                self.optional_fields |= c.getFields()
+            self.logger.debug("Using optional fields: %s", repr(self.fields))
+
+        # Remove mandatory fields from the optional list
+        # This can happen when more than one collector is able to provide
+        # the value
+        self.optional_fields = self.optional_fields.difference(self.fields)
+
+        if self.plotter is not None:
+            self.plotter.setFields(self.fields.union(self.optional_fields))
 
         data = {}
         for c in self.collectors:
             try:
                 for (key, val) in c.collect().items():
-                    if key not in data:
+                    if key not in data or data[key] is None:
                         data[key] = val
             except Collector.CollectionError, e:
                 self._disp_collection_error("Collection error: %s" % e.msg)
@@ -83,11 +97,16 @@
                 self._set_not_ready("Fatal Collector error: %s" % e.msg)
                 self.terminate()
                 return None
-        if set(data) != self.fields:
+
+        if not set(data).issuperset(self.fields):
             self._set_not_ready("Incomplete data: missing %s" % \
                                 (self.fields - set(data)))
             return None
 
+        # put None to all unset (optional) fields
+        for k in self.optional_fields:
+            data.setdefault(k, None)
+
         self.data_sem.acquire()
         self.statistics.append(data)
         if len(self.statistics) > self.config.getint('main', 
'sample-history-length'):
diff --git a/mom/Policy/Parser.py b/mom/Policy/Parser.py
index f3be3dc..89b75f3 100644
--- a/mom/Policy/Parser.py
+++ b/mom/Policy/Parser.py
@@ -302,7 +302,7 @@
                     '<<': 'shl', '>>': 'shr',
                     '==': 'eq', '!=': 'neq',
                     'and': 'and', 'or': 'or', 'not': 'not',
-                    'min': 'min', 'max': 'max' }
+                    'min': 'min', 'max': 'max', "valid": "valid" }
 
     def __init__(self):
         GenericEvaluator.__init__(self)
@@ -446,6 +446,9 @@
     def c_max(self, *args):
         return max(args)
 
+    def c_valid(self, *args):
+        return all(v is not None for v in args)
+
 def get_code(e, string):
     try:
         scanner = Scanner(e.get_operators())
diff --git a/tests/ParserTests.py b/tests/ParserTests.py
index 8a04636..73b65fc 100644
--- a/tests/ParserTests.py
+++ b/tests/ParserTests.py
@@ -20,6 +20,7 @@
 class TestEval(unittest.TestCase):
     def setUp(self):
         self.e = Parser.Evaluator()
+        self.e.stack.set("None", None, alloc=True)
 
     def verify(self, pol, expected):
         results = Parser.eval(self.e, pol)
@@ -271,5 +272,17 @@
         """
         self.assertRaises(Parser.PolicyError, Parser.eval, self.e, pol)
 
+    def test_valid(self):
+        pol = """
+        (valid 0 1 2 "")
+        """
+        self.verify(pol, [True])
+
+    def test_invalid(self):
+        pol = """
+        (valid None)
+        """
+        self.verify(pol, [False])
+
 if __name__ == '__main__':
     unittest.main()


-- 
To view, visit http://gerrit.ovirt.org/21050
To unsubscribe, visit http://gerrit.ovirt.org/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I3a93f0985870b431c315918b14fee6629eac70fb
Gerrit-PatchSet: 1
Gerrit-Project: mom
Gerrit-Branch: master
Gerrit-Owner: Martin Sivák <[email protected]>
_______________________________________________
Engine-patches mailing list
[email protected]
http://lists.ovirt.org/mailman/listinfo/engine-patches

Reply via email to