regulators: Add check infinite loops function.

Add check_infinite_loops function.
It checks whether infinite loop happened in the config file.

Signed-off-by: Bob King <Bob_King@wistron.com>
Change-Id: I34e7feb6e6200687538c1a68ba7e3cb785055d6e
diff --git a/phosphor-regulators/tools/validate-regulators-config.py b/phosphor-regulators/tools/validate-regulators-config.py
index 0c2e185..159f0df 100644
--- a/phosphor-regulators/tools/validate-regulators-config.py
+++ b/phosphor-regulators/tools/validate-regulators-config.py
@@ -13,6 +13,42 @@
 def handle_validation_error():
     sys.exit("Validation failed.")
 
+def check_infinite_loops_in_rule(config_json, rule_json, call_stack=[]):
+    r"""
+    Check if a 'run_rule' action in the specified rule causes an
+    infinite loop.
+    config_json: Configuration file JSON.
+    rule_json: A rule in the JSON config file.
+    call_stack: Current call stack of rules.
+    """
+
+    call_stack.append(rule_json['id'])
+    for action in rule_json.get('actions', {}):
+        if 'run_rule' in action:
+            run_rule_id = action['run_rule']
+            if run_rule_id in call_stack:
+                call_stack.append(run_rule_id)
+                sys.stderr.write(\
+               "Infinite loop caused by run_rule actions.\n"+\
+                str(call_stack)+'\n')
+                handle_validation_error()
+            else:
+                for rule in config_json.get('rules', {}):
+                    if rule['id'] == run_rule_id:
+                        check_infinite_loops_in_rule(\
+                        config_json, rule, call_stack)
+    call_stack.pop()
+
+def check_infinite_loops(config_json):
+    r"""
+    Check if rule in config file is called recursively, causing an
+    infinite loop.
+    config_json: Configuration file JSON
+    """
+
+    for rule in config_json.get('rules', {}):
+        check_infinite_loops_in_rule(config_json, rule)
+
 def check_duplicate_object_id(config_json):
     r"""
     Check that there aren't any JSON objects with the same 'id' property value.
@@ -155,4 +191,8 @@
         sys.exit("Error: Configuration file is required.")
 
     config_json = validate_schema(args.configuration_file, args.schema_file)
+
     check_for_duplicates(config_json)
+
+    check_infinite_loops(config_json)
+