fix: SCALE_IN action not honoring specified node count

The SCALE_IN action in the lb_policy module was removing only
one node from the load balancer, regardless of the specified
count when the count was greater than 1. This was due to a
hard-coded count of 1 in the _get_delete_candidates function.

The root cause has been addressed by updating the
_get_delete_candidates function to dynamically handle the count
for SCALE_IN. The count is now retrieved from the action inputs,
and if not specified or invalid, it defaults to 1.

Closes-Bug: #2048099
Change-Id: I9ff12dec26f4c558ef5ef84de87668e9668cec80
This commit is contained in:
Nguyen Ngoc Hieu 2024-01-05 02:26:04 +07:00
parent 5c0fae0453
commit 2b66935763
3 changed files with 42 additions and 9 deletions

View File

@ -0,0 +1,6 @@
---
fixes:
- |
Addresses an issue related to the SCALE_IN action. The bug caused
the removal of only one node from the load balancer even when the
count of inputs was greater than 1.

View File

@ -525,7 +525,7 @@ class LoadBalancingPolicy(base.Policy):
else:
count = action.data['deletion']['count']
else: # action.action == consts.CLUSTER_SCALE_IN
count = 1
count = action.inputs.get('count', 1)
elif action.action == consts.CLUSTER_REPLACE_NODES:
candidates = list(action.inputs['candidates'].keys())
count = len(candidates)

View File

@ -516,18 +516,21 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
node1 = mock.Mock(id='node1')
node2 = mock.Mock(id='node2')
node3 = mock.Mock(id='node3')
cluster = mock.Mock()
cluster.nodes = [node1, node2, node3]
action = mock.Mock(action=consts.CLUSTER_SCALE_IN, data={})
action.entity = cluster
cluster = mock.Mock(nodes=[node1, node2, node3])
action = mock.Mock(
action=consts.CLUSTER_SCALE_IN,
entity=cluster,
data={},
inputs={'count': 1}
)
m_nodes_random.return_value = ['node3']
m_nodes_random.return_value = ['node1', 'node3']
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
res = policy._get_delete_candidates('CLUSTERID', action)
res = policy._get_delete_candidates('CLUSTER_ID', action)
m_nodes_random.assert_called_once_with([node1, node2, node3], 1)
self.assertEqual(['node1', 'node3'], res)
self.assertEqual(['node3'], res)
@mock.patch.object(scaleutils, 'parse_resize_params')
@mock.patch.object(scaleutils, 'nodes_by_random')
@ -618,6 +621,30 @@ class TestLoadBalancingPolicy(base.SenlinTestCase):
res = policy._get_delete_candidates('CLUSTERID', action)
self.assertEqual(['node3'], res)
@mock.patch.object(scaleutils, 'nodes_by_random')
def test_get_delete_candidates_no_deletion_data_count_gt_one_scale_in(
self, m_nodes_random
):
self.context = utils.dummy_context()
node1 = mock.Mock(id='node1')
node2 = mock.Mock(id='node2')
node3 = mock.Mock(id='node3')
cluster = mock.Mock(nodes=[node1, node2, node3])
action = mock.Mock(
action=consts.CLUSTER_SCALE_IN,
entity=cluster,
data={},
inputs={'count': 2}
)
m_nodes_random.return_value = ['node1', 'node3']
policy = lb_policy.LoadBalancingPolicy('test-policy', self.spec)
res = policy._get_delete_candidates('CLUSTER_ID', action)
m_nodes_random.assert_called_once_with([node1, node2, node3], 2)
self.assertEqual(['node1', 'node3'], res)
@mock.patch.object(cluster_policy.ClusterPolicy, 'load')
@mock.patch.object(lb_policy.LoadBalancingPolicy, '_extract_policy_data')