From dcd440d07c0b8d0e34bbac96f28351e001486ee3 Mon Sep 17 00:00:00 2001 From: Eric K Date: Wed, 28 Sep 2016 14:25:10 -0700 Subject: [PATCH] Fix rule sync for head-only rules synchronize_rules does not work on head-only rules because meta-data is not stored in memory on these rules. This patch separately syncs head-only rules based on rule content rather than metadata. Change-Id: I4e29ad4fff402416eb131e08fac0ee9da9a0ebaf --- congress/policy_engines/agnostic.py | 66 +++++++++++++++++++++++------ 1 file changed, 54 insertions(+), 12 deletions(-) diff --git a/congress/policy_engines/agnostic.py b/congress/policy_engines/agnostic.py index 11c7b7dfe..52550b45a 100644 --- a/congress/policy_engines/agnostic.py +++ b/congress/policy_engines/agnostic.py @@ -2244,25 +2244,43 @@ class DseRuntime (Runtime, data_service.DataService): LOG.info("Synchronizing rules on node %s", self.node.node_id) # Read rules from DB. - configured_rules = [{'rule': r.rule, - 'id': r.id, - 'comment': r.comment, - 'name': r.name, - 'policy_name': r.policy_name} - for r in db_policy_rules.get_policy_rules()] + + configured_rules = [] + configured_facts = [] + for r in db_policy_rules.get_policy_rules(): + if ':-' in r.rule: # if rule has body + configured_rules.append({'rule': r.rule, + 'id': r.id, + 'comment': r.comment, + 'name': r.name, + 'policy_name': r.policy_name}) + else: # head-only rule, ie., fact + configured_facts.append( + {'rule': self.parse1(r.rule).pretty_str(), + # Note: parse to remove effect of extraneous formatting + 'policy_name': r.policy_name}) # Read rules from engine policies = {n: self.policy_object(n) for n in self.policy_names()} active_policy_rules = [] + active_policy_facts = [] for policy_name, policy in policies.items(): if policy.kind != base.DATASOURCE_POLICY_TYPE: for active_rule in policy.content(): - active_policy_rules.append( - {'rule': active_rule.original_str, - 'id': active_rule.id, - 'comment': active_rule.comment, - 'name': active_rule.name, - 'policy_name': policy_name}) + # FIXME: This assumes r.original_str is None iff + # r is a head-only rule (fact). This works in non-recursive + # policy but not in recursive policies + if active_rule.original_str is None: + active_policy_facts.append( + {'rule': str(active_rule.head), + 'policy_name': policy_name}) + else: + active_policy_rules.append( + {'rule': active_rule.original_str, + 'id': active_rule.id, + 'comment': active_rule.comment, + 'name': active_rule.name, + 'policy_name': policy_name}) # ALEX: the Rule object does not have fields like the rule-string or # id or comment. We can add those fields to the Rule object, as long @@ -2272,6 +2290,8 @@ class DseRuntime (Runtime, data_service.DataService): # instead. changes = [] + + # add configured rules for r in configured_rules: if r not in active_policy_rules: LOG.debug("adding rule %s", str(r)) @@ -2286,6 +2306,17 @@ class DseRuntime (Runtime, data_service.DataService): target=r['policy_name']) changes.append(event) + # add configured facts + for r in configured_facts: + if r not in active_policy_facts: + LOG.debug("adding rule %s", str(r)) + parsed_rule = self.parse1(r['rule']) + event = compile.Event(formula=parsed_rule, + insert=True, + target=r['policy_name']) + changes.append(event) + + # remove active rules not configured for r in active_policy_rules: if r not in configured_rules: LOG.debug("removing rule %s", str(r)) @@ -2299,6 +2330,17 @@ class DseRuntime (Runtime, data_service.DataService): insert=False, target=r['policy_name']) changes.append(event) + + # remove active facts not configured + for r in active_policy_facts: + if r not in configured_facts: + LOG.debug("removing rule %s", str(r)) + parsed_rule = self.parse1(r['rule']) + event = compile.Event(formula=parsed_rule, + insert=False, + target=r['policy_name']) + changes.append(event) + permitted, changes = self.process_policy_update(changes) LOG.debug("synchronize_rules, permitted %d, made %d changes on " "node %s", permitted, len(changes), self.node.node_id)