Merge "Computes transitive relationships in murano model"
This commit is contained in:
commit
bcb142cf7d
@ -56,8 +56,41 @@ class CongressRulesManager(object):
|
||||
self._rules = [self._create_relationship(rule, object_ids)
|
||||
for rule in self._rules]
|
||||
|
||||
relations = [(rel.source_id, rel.target_id)
|
||||
for rel in self._rules
|
||||
if isinstance(rel, RelationshipRule)]
|
||||
closure = self.transitive_closure(relations)
|
||||
|
||||
for rel in closure:
|
||||
self._rules.append(ConnectedRule(rel[0], rel[1]))
|
||||
|
||||
return self._rules
|
||||
|
||||
@staticmethod
|
||||
def transitive_closure(relations):
|
||||
"""Computes transitive closure on a directed graph.
|
||||
|
||||
In other words computes reachability within the graph.
|
||||
E.g. {(1, 2), (2, 3)} -> {(1, 2), (2, 3), (1, 3)}
|
||||
(1, 3) was added because there is path from 1 to 3 in the graph.
|
||||
|
||||
:param relations: list of relations/edges in form of tuples
|
||||
:return: transitive closure including original relations
|
||||
"""
|
||||
closure = set(relations)
|
||||
while True:
|
||||
# Attempts to discover new transitive relations
|
||||
# by joining 2 subsequent relations/edges within the graph.
|
||||
new_relations = {(x, w) for x, y in closure
|
||||
for q, w in closure if q == y}
|
||||
# Creates union with already discovered relations.
|
||||
closure_until_now = closure | new_relations
|
||||
# If no new relations were discovered in last cycle
|
||||
# the computation is finished.
|
||||
if closure_until_now == closure:
|
||||
return closure
|
||||
closure = closure_until_now
|
||||
|
||||
def _walk(self, obj, func):
|
||||
|
||||
if obj is None:
|
||||
@ -195,6 +228,16 @@ class RelationshipRule(object):
|
||||
self.source_id, self.target_id, self.rel_name)
|
||||
|
||||
|
||||
class ConnectedRule(object):
|
||||
def __init__(self, source_id, target_id):
|
||||
self.source_id = source_id
|
||||
self.target_id = target_id
|
||||
|
||||
def __str__(self):
|
||||
return 'murano:connected+("{0}", "{1}")'.format(
|
||||
self.source_id, self.target_id)
|
||||
|
||||
|
||||
class ParentTypeRule(object):
|
||||
def __init__(self, obj_id, type_name):
|
||||
self.obj_id = obj_id
|
||||
|
@ -71,6 +71,12 @@ class TestCongressRules(unittest.TestCase):
|
||||
|
||||
return rules_str
|
||||
|
||||
def test_transitive_closure(self):
|
||||
closure = congress.CongressRulesManager.transitive_closure(
|
||||
[(1, 2), (2, 3), (3, 4)])
|
||||
self.assertTrue((1, 4) in closure)
|
||||
self.assertTrue((2, 4) in closure)
|
||||
|
||||
def test_empty_model(self):
|
||||
congress_rules = congress.CongressRulesManager()
|
||||
rules = congress_rules.convert(None)
|
||||
@ -101,6 +107,17 @@ class TestCongressRules(unittest.TestCase):
|
||||
'murano:relationships+("0aafd67e-72e9-4ae0-bb62-fe724f77df2a", '
|
||||
'"ed8df2b0-ddd2-4009-b3c9-2e7a368f3cb8", "instance")' in rules_str)
|
||||
|
||||
def test_convert_model_transitive_relationships(self):
|
||||
rules_str = self._create_rules_str('model_with_relations.yaml')
|
||||
|
||||
self.assertTrue(
|
||||
'murano:connected+("50fa68ff-cd9a-4845-b573-2c80879d158d", '
|
||||
'"8ce94f23-f16a-40a1-9d9d-a877266c315d")' in rules_str)
|
||||
|
||||
self.assertTrue(
|
||||
'murano:connected+("8ce94f23-f16a-40a1-9d9d-a877266c315d", '
|
||||
'"fc6b8c41-166f-4fc9-a640-d82009e0a03d")' in rules_str)
|
||||
|
||||
def test_convert_model_complex(self):
|
||||
self._create_and_check_rules_str('model_complex')
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user