Exclude atomic rule from dependency graph
Dependency graph used by agnostic excludes positive literals of type compile.Literal. But when a policy is deleted, the facts in the policy are deleted as atomic rules of type compile.Rule. As a result, some nodes in the dependency graph are prematurely deleted because the deleting of facts (type compile.Rule) via policy delete decreased ref counters that had not been correspondingly increased by the adding of those same facts (type compile.Literal). When a dependency graph is thus corrupted, congress gives Internal Server Error on all future attempts to add/delete/sync rules. This patch fixes the problem by having agnostic treat an atomic rule (type compile.Rule) the same way it treats an atom (type compile.Literal) in the dependency graph -- ignore both. Closes-Bug: 1662809 Change-Id: I8080cbb7c375d90259f7b8a2a62d714ebe4aee5f
This commit is contained in:
parent
34a9e5fdec
commit
d635bad1ae
|
@ -1364,7 +1364,7 @@ class RuleDependencyGraph(utility.BagGraph):
|
|||
# TODO(thinrichs): should be able to have global_tablename
|
||||
# return a Tablename object and therefore build a graph
|
||||
# of Tablename objects instead of strings.
|
||||
if is_atom(formula):
|
||||
if is_atom_like(formula):
|
||||
if include_atoms:
|
||||
table = formula.table.global_tablename(theory)
|
||||
nodes.add(table)
|
||||
|
@ -1804,6 +1804,22 @@ def is_regular_rule(x):
|
|||
return (is_rule(x) and len(x.heads) == 1)
|
||||
|
||||
|
||||
def is_atom_rule(x):
|
||||
return is_regular_rule(x) and len(x.body) == 0 and is_literal(x.heads[0])
|
||||
|
||||
|
||||
def is_literal_rule(x):
|
||||
return is_regular_rule(x) and len(x.body) == 0 and is_literal(x.heads[0])
|
||||
|
||||
|
||||
def is_atom_like(x):
|
||||
return is_atom(x) or is_atom_rule(x)
|
||||
|
||||
|
||||
def is_literal_like(x):
|
||||
return is_literal(x) or is_literal_rule(x)
|
||||
|
||||
|
||||
def is_multi_rule(x):
|
||||
"""Returns True if X is a rule with multiple heads."""
|
||||
return (is_rule(x) and len(x.heads) != 1)
|
||||
|
|
|
@ -919,6 +919,26 @@ class TestMultipolicyRules(base.TestCase):
|
|||
self.assertEqual(len(errors), 1)
|
||||
self.assertIn("Rules are recursive", str(errors[0]))
|
||||
|
||||
def test_dependency_graph_policy_deletion(self):
|
||||
run = agnostic.Runtime()
|
||||
g = run.global_dependency_graph
|
||||
run.create_policy('test')
|
||||
rule = 'execute[nova:flavors.delete(id)] :- nova:flavors(id)'
|
||||
permitted, changes = run.insert(rule, target='test')
|
||||
self.assertTrue(permitted)
|
||||
run.create_policy('nova')
|
||||
run.insert('flavors(1)', target="nova")
|
||||
run.insert('flavors(2)', target="nova")
|
||||
run.insert('flavors(3)', target="nova")
|
||||
run.insert('flavors(4)', target="nova")
|
||||
|
||||
self.assertEqual(g.dependencies('test:nova:flavors.delete'),
|
||||
set(['nova:flavors', 'test:nova:flavors.delete']))
|
||||
run.delete_policy('nova')
|
||||
self.assertTrue(g.node_in('nova:flavors'))
|
||||
self.assertEqual(g.dependencies('test:nova:flavors.delete'),
|
||||
set(['nova:flavors', 'test:nova:flavors.delete']))
|
||||
|
||||
def test_dependency_graph(self):
|
||||
"""Test that dependency graph gets updated correctly."""
|
||||
run = agnostic.Runtime()
|
||||
|
|
Loading…
Reference in New Issue