revise lb policy to handle node_recover
this patch revises lb policy to handle node_recover action: 1. node is not member of lb pool, will add it to lb pool 2. node is already member of lb pool, but the recovery action is not 'RECREATE', do nothing 3. node is already member of lb pool, and the recovery action is 'RECREATE', need to remove it from lb pool and then add it to it since the ip of the resource has already been changed. Change-Id: I69fe9ca8e646682333b65f8c90dc1cf245153622
This commit is contained in:
parent
46694ac71b
commit
18aa65e1d2
@ -398,7 +398,7 @@ class LoadBalancingPolicy(base.Policy):
|
|||||||
candidates = None
|
candidates = None
|
||||||
if deletion is None:
|
if deletion is None:
|
||||||
if action.action == consts.NODE_DELETE:
|
if action.action == consts.NODE_DELETE:
|
||||||
candidates = [action.node.id]
|
candidates = [action.entity.id]
|
||||||
count = 1
|
count = 1
|
||||||
elif action.action == consts.CLUSTER_DEL_NODES:
|
elif action.action == consts.CLUSTER_DEL_NODES:
|
||||||
# Get candidates from action.input
|
# Get candidates from action.input
|
||||||
@ -503,20 +503,40 @@ class LoadBalancingPolicy(base.Policy):
|
|||||||
def _get_post_candidates(self, action):
|
def _get_post_candidates(self, action):
|
||||||
# This method will parse action data passed from action layer
|
# This method will parse action data passed from action layer
|
||||||
candidates = []
|
candidates = []
|
||||||
if action.action == consts.NODE_CREATE:
|
if (action.action == consts.NODE_CREATE or
|
||||||
candidates = [action.node.id]
|
action.action == consts.NODE_RECOVER):
|
||||||
elif action.action == consts.NODE_RECOVER:
|
candidates = [action.entity.id]
|
||||||
recovery = action.outputs.get('recovery', None)
|
|
||||||
if recovery is not None and 'action' in recovery:
|
|
||||||
action_name = recovery['action']
|
|
||||||
if action_name.upper() == consts.RECOVER_RECREATE:
|
|
||||||
candidates = recovery.get('node', [])
|
|
||||||
else:
|
else:
|
||||||
creation = action.data.get('creation', None)
|
creation = action.data.get('creation', None)
|
||||||
candidates = creation.get('nodes', []) if creation else []
|
candidates = creation.get('nodes', []) if creation else []
|
||||||
|
|
||||||
return candidates
|
return candidates
|
||||||
|
|
||||||
|
def _process_recovery(self, candidates, policy, driver, action):
|
||||||
|
# Process node recovery action
|
||||||
|
node = action.entity
|
||||||
|
data = node.data
|
||||||
|
lb_member = data.get('lb_member', None)
|
||||||
|
recovery = data.pop('recovery', None)
|
||||||
|
values = {}
|
||||||
|
|
||||||
|
# lb_member is None, need to add to lb pool
|
||||||
|
if not lb_member:
|
||||||
|
values['data'] = data
|
||||||
|
no.Node.update(action.context, values)
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
# was a member of lb pool, check whether has been recreated
|
||||||
|
if recovery is not None and recovery == consts.RECOVER_RECREATE:
|
||||||
|
self._remove_member(candidates, policy, action, driver,
|
||||||
|
handle_err=False)
|
||||||
|
data.pop('lb_member', None)
|
||||||
|
values['data'] = data
|
||||||
|
no.Node.update(action.context, values)
|
||||||
|
return candidates
|
||||||
|
|
||||||
|
return None
|
||||||
|
|
||||||
def pre_op(self, cluster_id, action):
|
def pre_op(self, cluster_id, action):
|
||||||
"""Routine to be called before an action has been executed.
|
"""Routine to be called before an action has been executed.
|
||||||
|
|
||||||
@ -573,8 +593,11 @@ class LoadBalancingPolicy(base.Policy):
|
|||||||
cp = cluster_policy.ClusterPolicy.load(action.context, cluster_id,
|
cp = cluster_policy.ClusterPolicy.load(action.context, cluster_id,
|
||||||
self.id)
|
self.id)
|
||||||
if action.action == consts.NODE_RECOVER:
|
if action.action == consts.NODE_RECOVER:
|
||||||
self._remove_member(candidates, cp, action, lb_driver,
|
candidates = self._process_recovery(
|
||||||
handle_err=False)
|
candidates, cp, lb_driver, action)
|
||||||
|
if not candidates:
|
||||||
|
return
|
||||||
|
|
||||||
# Add new nodes to lb pool
|
# Add new nodes to lb pool
|
||||||
failed_nodes = self._add_member(candidates, cp, action, lb_driver)
|
failed_nodes = self._add_member(candidates, cp, action, lb_driver)
|
||||||
if failed_nodes:
|
if failed_nodes:
|
||||||
|
@ -264,51 +264,26 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
|
|||||||
self.assertEqual((False, 'Failed in adding node into lb pool'), res)
|
self.assertEqual((False, 'Failed in adding node into lb pool'), res)
|
||||||
self.lb_driver.lb_delete.assert_called_once_with(**lb_data)
|
self.lb_driver.lb_delete.assert_called_once_with(**lb_data)
|
||||||
|
|
||||||
def test_get_post_candidates_node_create(self):
|
def test_post_candidates_node_recover_reboot(self):
|
||||||
action = mock.Mock(action=consts.NODE_CREATE,
|
node = mock.Mock(id='NODE1_ID')
|
||||||
node=mock.Mock(id='NODE'))
|
action = mock.Mock(action=consts.NODE_RECOVER)
|
||||||
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
action.entity = node
|
||||||
|
|
||||||
candidates = policy._get_post_candidates(action)
|
|
||||||
|
|
||||||
self.assertEqual(['NODE'], candidates)
|
|
||||||
|
|
||||||
def test_post_candidates_node_recover(self):
|
|
||||||
action = mock.Mock(action=consts.NODE_RECOVER,
|
|
||||||
outputs={
|
|
||||||
'recovery': {
|
|
||||||
'action': consts.RECOVER_RECREATE,
|
|
||||||
'node': ['NODE1_ID']
|
|
||||||
}
|
|
||||||
})
|
|
||||||
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
||||||
|
|
||||||
candidates = policy._get_post_candidates(action)
|
candidates = policy._get_post_candidates(action)
|
||||||
|
|
||||||
self.assertEqual(['NODE1_ID'], candidates)
|
self.assertEqual(['NODE1_ID'], candidates)
|
||||||
|
|
||||||
def test_post_candidates_node_recover_reboot(self):
|
|
||||||
action = mock.Mock(action=consts.NODE_RECOVER,
|
|
||||||
outputs={
|
|
||||||
'recovery': {
|
|
||||||
'action': consts.RECOVER_REBOOT,
|
|
||||||
'node': ['NODE1_ID']
|
|
||||||
}
|
|
||||||
})
|
|
||||||
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
|
||||||
|
|
||||||
candidates = policy._get_post_candidates(action)
|
|
||||||
|
|
||||||
self.assertEqual([], candidates)
|
|
||||||
|
|
||||||
def test_post_candidates_node_recover_empty(self):
|
def test_post_candidates_node_recover_empty(self):
|
||||||
|
node = mock.Mock(id='NODE1_ID')
|
||||||
action = mock.Mock(action=consts.NODE_RECOVER,
|
action = mock.Mock(action=consts.NODE_RECOVER,
|
||||||
outputs={})
|
outputs={})
|
||||||
|
action.entity = node
|
||||||
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
||||||
|
|
||||||
candidates = policy._get_post_candidates(action)
|
candidates = policy._get_post_candidates(action)
|
||||||
|
|
||||||
self.assertEqual([], candidates)
|
self.assertEqual(['NODE1_ID'], candidates)
|
||||||
|
|
||||||
def test_post_candidates_cluster_resize(self):
|
def test_post_candidates_cluster_resize(self):
|
||||||
action = mock.Mock(action=consts.CLUSTER_RESIZE,
|
action = mock.Mock(action=consts.CLUSTER_RESIZE,
|
||||||
@ -325,7 +300,7 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
|
|||||||
|
|
||||||
def test_get_delete_candidates_for_node_delete(self):
|
def test_get_delete_candidates_for_node_delete(self):
|
||||||
action = mock.Mock(action=consts.NODE_DELETE, inputs={}, data={},
|
action = mock.Mock(action=consts.NODE_DELETE, inputs={}, data={},
|
||||||
node=mock.Mock(id='NODE_ID'))
|
entity=mock.Mock(id='NODE_ID'))
|
||||||
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
||||||
|
|
||||||
res = policy._get_delete_candidates('CLUSTERID', action)
|
res = policy._get_delete_candidates('CLUSTERID', action)
|
||||||
@ -732,22 +707,18 @@ class TestLoadBalancingPolicyOperations(base.SenlinTestCase):
|
|||||||
self.assertFalse(m_remove.called)
|
self.assertFalse(m_remove.called)
|
||||||
|
|
||||||
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_add_member')
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_add_member')
|
||||||
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_remove_member')
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_process_recovery')
|
||||||
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_get_post_candidates')
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_get_post_candidates')
|
||||||
def test_post_op_node_recover(self, m_get, m_remove, m_add,
|
def test_post_op_node_recover(self, m_get, m_recovery, m_add,
|
||||||
m_candidates, m_load):
|
m_candidates, m_load):
|
||||||
cid = 'CLUSTER_ID'
|
cid = 'CLUSTER_ID'
|
||||||
cluster = mock.Mock(user='user1', project='project1')
|
node = mock.Mock(user='user1', project='project1', id='NODE1')
|
||||||
action = mock.Mock(context='action_context',
|
action = mock.Mock(context='action_context',
|
||||||
action=consts.NODE_RECOVER,
|
action=consts.NODE_RECOVER,
|
||||||
data={},
|
data={},
|
||||||
outputs={
|
outputs={})
|
||||||
'recovery': {
|
action.entity = node
|
||||||
'action': consts.RECOVER_RECREATE,
|
m_recovery.return_value = ['NODE1']
|
||||||
'node': ['NODE1']
|
|
||||||
}
|
|
||||||
})
|
|
||||||
action.entity = cluster
|
|
||||||
m_get.return_value = ['NODE1']
|
m_get.return_value = ['NODE1']
|
||||||
cp = mock.Mock()
|
cp = mock.Mock()
|
||||||
m_load.return_value = cp
|
m_load.return_value = cp
|
||||||
@ -762,8 +733,8 @@ class TestLoadBalancingPolicyOperations(base.SenlinTestCase):
|
|||||||
m_get.assert_called_once_with(action)
|
m_get.assert_called_once_with(action)
|
||||||
m_load.assert_called_once_with('action_context', cid, policy.id)
|
m_load.assert_called_once_with('action_context', cid, policy.id)
|
||||||
m_add.assert_called_once_with(['NODE1'], cp, action, self.lb_driver)
|
m_add.assert_called_once_with(['NODE1'], cp, action, self.lb_driver)
|
||||||
m_remove.assert_called_once_with(['NODE1'], cp, action, self.lb_driver,
|
m_recovery.assert_called_once_with(['NODE1'], cp, self.lb_driver,
|
||||||
handle_err=False)
|
action)
|
||||||
|
|
||||||
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_add_member')
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_add_member')
|
||||||
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_remove_member')
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_remove_member')
|
||||||
@ -989,3 +960,58 @@ class TestLoadBalancingPolicyOperations(base.SenlinTestCase):
|
|||||||
|
|
||||||
m_remove.assert_called_once_with(
|
m_remove.assert_called_once_with(
|
||||||
['NODE1_ID'], mock.ANY, action, self.lb_driver)
|
['NODE1_ID'], mock.ANY, action, self.lb_driver)
|
||||||
|
|
||||||
|
@mock.patch.object(no.Node, 'update')
|
||||||
|
def test__process_recovery_not_lb_member(self, m_update, m1, m2):
|
||||||
|
node = mock.Mock(id='NODE', data={})
|
||||||
|
action = mock.Mock(
|
||||||
|
action=consts.NODE_RECOVER,
|
||||||
|
context='action_context')
|
||||||
|
action.entity = node
|
||||||
|
|
||||||
|
cp = mock.Mock()
|
||||||
|
|
||||||
|
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
||||||
|
res = policy._process_recovery(['NODE'], cp, self.lb_driver, action)
|
||||||
|
|
||||||
|
self.assertEqual(['NODE'], res)
|
||||||
|
m_update.assert_called_once_with(action.context, {'data': {}})
|
||||||
|
|
||||||
|
@mock.patch.object(no.Node, 'update')
|
||||||
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_remove_member')
|
||||||
|
def test__process_recovery_reboot(self, m_remove, m_update, m1, m2):
|
||||||
|
node = mock.Mock(id='NODE', data={'lb_member': 'mem_1'})
|
||||||
|
action = mock.Mock(
|
||||||
|
action=consts.NODE_RECOVER,
|
||||||
|
context='action_context')
|
||||||
|
action.entity = node
|
||||||
|
|
||||||
|
cp = mock.Mock()
|
||||||
|
|
||||||
|
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
||||||
|
res = policy._process_recovery(['NODE'], cp, self.lb_driver, action)
|
||||||
|
|
||||||
|
self.assertIsNone(res)
|
||||||
|
|
||||||
|
self.assertFalse(m_remove.called)
|
||||||
|
self.assertFalse(m_update.called)
|
||||||
|
|
||||||
|
@mock.patch.object(no.Node, 'update')
|
||||||
|
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_remove_member')
|
||||||
|
def test__process_recovery_recreate(self, m_remove, m_update, m1, m2):
|
||||||
|
node = mock.Mock(id='NODE', data={'lb_member': 'mem_1',
|
||||||
|
'recovery': 'RECREATE'})
|
||||||
|
action = mock.Mock(
|
||||||
|
action=consts.NODE_RECOVER,
|
||||||
|
context='action_context')
|
||||||
|
action.entity = node
|
||||||
|
|
||||||
|
cp = mock.Mock()
|
||||||
|
|
||||||
|
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
|
||||||
|
res = policy._process_recovery(['NODE'], cp, self.lb_driver, action)
|
||||||
|
|
||||||
|
self.assertEqual(['NODE'], res)
|
||||||
|
m_remove.assert_called_once_with(['NODE'], cp, action, self.lb_driver,
|
||||||
|
handle_err=False)
|
||||||
|
m_update.assert_called_once_with(action.context, {'data': {}})
|
||||||
|
Loading…
Reference in New Issue
Block a user