Improve DB API for node dependency

This patch improves the DB APIs dealing with node dependency. A node can
be depended by either another node or a profile object. The improved
version will be able to handle both cases.

Change-Id: I78a0d4c736a028f0475455a4a53bd53a924983b9
This commit is contained in:
tengqm 2016-12-13 22:47:21 -05:00
parent 72925bac5d
commit 69353471d6
2 changed files with 77 additions and 26 deletions

View File

@ -310,43 +310,61 @@ def node_update(context, node_id, values):
cluster.save(session)
def node_add_dependents(context, depended_node, node):
'''Add dependency between nodes.
def node_add_dependents(context, depended, dependent, dep_type=None):
"""Add dependency between nodes.
:param depended_node: ID of the depended node.
:param node: ID of the node which has dependencies on other nodes.
:param depended: ID of the depended dependent.
:param dependent: ID of the dependent node or profile which has
dependencies on depended node.
:param dep_type: The type of dependency. It can be 'node' indicating a
dependency beween two nodes; or 'profile' indicating a
dependency from profile to node.
:raises ResourceNotFound: The specified node does not exist in database.
'''
"""
with session_for_write() as session:
dep_node = session.query(models.Node).get(depended_node)
dep_node = session.query(models.Node).get(depended)
if not dep_node:
raise exception.ResourceNotFound(type='node', id=depended_node)
raise exception.ResourceNotFound(type='node', id=depended)
nodes = dep_node.dependents.get('nodes', [])
nodes.append(node)
dep_node.dependents.update({'nodes': nodes})
if dep_type is None or dep_type == 'node':
key = 'nodes'
else:
key = 'profiles'
dependents = dep_node.dependents.get(key, [])
dependents.append(dependent)
dep_node.dependents.update({key: dependents})
dep_node.save(session)
def node_remove_dependents(context, depended_node, node):
'''Remove dependency between nodes.
def node_remove_dependents(context, depended, dependent, dep_type=None):
"""Remove dependency between nodes.
:param depended: ID of the depended node.
:param dependent: ID of the node or profile which has dependencies on
the depended node.
:param dep_type: The type of dependency. It can be 'node' indicating a
dependency beween two nodes; or 'profile' indicating a
dependency from profile to node.
:param depended_node: ID of the depended node.
:param node: ID of the node which has dependencies on other nodes.
:raises ResourceNotFound: The specified node does not exist in database.
'''
"""
with session_for_write() as session:
dep_node = session.query(models.Node).get(depended_node)
dep_node = session.query(models.Node).get(depended)
if not dep_node:
raise exception.ResourceNotFound(type='node', id=depended_node)
raise exception.ResourceNotFound(type='node', id=depended)
nodes = dep_node.dependents.get('nodes', [])
if node in nodes:
nodes.remove(node)
if len(nodes) > 0:
dep_node.dependents.update({'nodes': nodes})
if dep_type is None or dep_type == 'node':
key = 'nodes'
else:
key = 'profiles'
dependents = dep_node.dependents.get(key, [])
if dependent in dependents:
dependents.remove(dependent)
if len(dependents) > 0:
dep_node.dependents.update({key: dependents})
else:
dep_node.dependents.pop('nodes')
dep_node.dependents.pop(key)
dep_node.save(session)

View File

@ -162,7 +162,7 @@ class DBAPINodeTest(base.SenlinTestCase):
names = [node.name for node in nodes]
[self.assertIn(val['name'], names) for val in values]
def test_node_add_dependents(self):
def test_node_add_node_dependents(self):
node_id = 'host_node'
node = shared.create_node(self.ctx, None, self.profile,
id=node_id, name='node-1')
@ -176,7 +176,25 @@ class DBAPINodeTest(base.SenlinTestCase):
nodes = new_node.dependents['nodes']
self.assertEqual(['NODE1', 'NODE2'], nodes)
def test_node_remove_dependents(self):
def test_node_add_profile_dependents(self):
node_id = 'host_node'
new_profile = shared.create_profile(self.ctx)
node = shared.create_node(self.ctx, None, self.profile,
id=node_id, name='node-1')
db_api.node_add_dependents(self.ctx, node_id, new_profile.id,
'profile')
node = db_api.node_get(self.ctx, node_id)
nodes = node.dependents['profiles']
self.assertEqual([new_profile.id], nodes)
new_profile_1 = shared.create_profile(self.ctx)
db_api.node_add_dependents(self.ctx, node_id, new_profile_1.id,
'profile')
new_node = db_api.node_get(self.ctx, node_id)
nodes = new_node.dependents['profiles']
self.assertEqual([new_profile.id, new_profile_1.id], nodes)
def test_node_remove_node_dependents(self):
node_id = 'host_node'
dependents = {'nodes': ['NODE1', 'NODE2']}
node = shared.create_node(self.ctx, None, self.profile,
@ -186,7 +204,22 @@ class DBAPINodeTest(base.SenlinTestCase):
dependents = node.dependents
self.assertEqual({'nodes': ['NODE2']}, dependents)
db_api.node_remove_dependents(self.ctx, node_id, 'NODE2')
db_api.node_remove_dependents(self.ctx, node_id, 'NODE2', 'node')
node = db_api.node_get(self.ctx, node_id)
dependents = node.dependents
self.assertEqual({}, dependents)
def test_node_remove_profile_dependents(self):
node_id = 'host_node'
dependents = {'profiles': ['P1', 'P2']}
node = shared.create_node(self.ctx, None, self.profile,
id=node_id, dependents=dependents)
db_api.node_remove_dependents(self.ctx, node_id, 'P1', 'profile')
node = db_api.node_get(self.ctx, node_id)
dependents = node.dependents
self.assertEqual({'profiles': ['P2']}, dependents)
db_api.node_remove_dependents(self.ctx, node_id, 'P2', 'profile')
node = db_api.node_get(self.ctx, node_id)
dependents = node.dependents
self.assertEqual({}, dependents)