Пример #1
0
    def test_pre_op_candidates_provided(self):
        action = mock.Mock()
        action.context = self.context
        policy = dp.DeletionPolicy('test-policy', self.spec)

        # Both 'count' and 'candidates' are provided in deletion
        # field of action data
        action.data = {
            'deletion': {
                'count': 2,
                'candidates': [
                    self.nodes_p1[0],
                    self.nodes_p2[2],
                ],
            }
        }
        policy.pre_op(self.cluster['id'], action)
        pd = {
            'status': 'OK',
            'reason': 'Candidates generated',
            'deletion': {
                'count': 2,
                'candidates': [self.nodes_p1[0], self.nodes_p2[2]],
                'destroy_after_deletion': True,
                'grace_period': 60,
            }
        }
        self.assertEqual(pd, action.data)
        action.store.assert_called_with(self.context)
Пример #2
0
    def test_update_action_override(self):
        action = mock.Mock()
        action.data = {
            'deletion': {
                'count': 3,
            }
        }

        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy._update_action(action, ['N1', 'N2'])

        pd = {
            'status': 'OK',
            'reason': 'Candidates generated',
            'deletion': {
                'count': 2,
                'candidates': ['N1', 'N2'],
                'destroy_after_deletion': True,
                'grace_period': 60,
                'reduce_desired_capacity': False,
            }
        }
        self.assertEqual(pd, action.data)
        action.store.assert_called_with(action.context)
Пример #3
0
    def test_pre_op_with_zone_decisions(self, mock_load, mock_select,
                                        mock_update):
        action = mock.Mock()
        action.context = self.context
        action.inputs = {}
        action.data = {
            'deletion': {
                'count': 2,
                'zones': {
                    'AZ1': 1,
                    'AZ2': 1
                }
            }
        }

        cluster = mock.Mock(nodes=['a', 'b', 'c'])
        mock_load.return_value = cluster
        mock_select.return_value = ['NODE1', 'NODE2']

        policy = dp.DeletionPolicy('test-policy', self.spec)
        policy.pre_op('FAKE_ID', action)

        mock_update.assert_called_once_with(action, ['NODE1', 'NODE2'])
        mock_load.assert_called_once_with(action.context,
                                          cluster=None, cluster_id='FAKE_ID')
        mock_select.assert_called_once_with(cluster, {'AZ1': 1, 'AZ2': 1})
Пример #4
0
    def test_pre_op_resize_not_deletion(self, mock_get, mock_parse,
                                        mock_update):
        def fake_parse(a, c):
            a.data = {}
            return 'OK', 'cool'

        action = mock.Mock()
        action.context = self.context
        action.action = consts.CLUSTER_RESIZE
        action.inputs = {}

        db_cluster = mock.Mock()
        mock_get.return_value = db_cluster
        mock_parse.side_effect = fake_parse

        policy = dp.DeletionPolicy('test-policy', self.spec)
        # a simulation of non-deletion RESZIE
        action.data = {}

        policy.pre_op('FAKE_ID', action)

        mock_get.assert_called_once_with(action.context, 'FAKE_ID',
                                         project_safe=True)
        mock_parse.assert_called_once_with(action, db_cluster)
        self.assertEqual(0, mock_update.call_count)
Пример #5
0
    def test__victims_by_zones_profile_age(self, mock_select):
        cluster = mock.Mock()
        node1 = mock.Mock(id=1)
        node2 = mock.Mock(id=2)
        node3 = mock.Mock(id=3)
        cluster.nodes_by_zone.side_effect = [
            [node1], [node2, node3]
        ]

        mock_select.side_effect = [['1'], ['2']]

        self.spec['properties']['criteria'] = 'OLDEST_PROFILE_FIRST'
        policy = dp.DeletionPolicy('test-policy', self.spec)

        res = policy._victims_by_zones(cluster, {'AZ1': 1, 'AZ2': 1})
        self.assertEqual(['1', '2'], res)
        mock_select.assert_has_calls(
            [
                mock.call([node1], 1),
                mock.call([node2, node3], 1)
            ],
        )
        cluster.nodes_by_zone.assert_has_calls(
            [mock.call('AZ1'), mock.call('AZ2')],
        )
Пример #6
0
    def test__victims_by_zones_age_youngest(self, mock_select):
        cluster = mock.Mock()
        node1 = mock.Mock(id=1)
        node2 = mock.Mock(id=3)
        node3 = mock.Mock(id=5)
        cluster.nodes_by_zone.side_effect = [
            [node1], [node2, node3]
        ]

        mock_select.side_effect = [['1'], ['3', '5']]

        self.spec['properties']['criteria'] = 'YOUNGEST_FIRST'
        policy = dp.DeletionPolicy('test-policy', self.spec)

        res = policy._victims_by_zones(cluster, {'AZ5': 1, 'AZ6': 2})
        self.assertEqual(['1', '3', '5'], res)
        mock_select.assert_has_calls(
            [
                mock.call([node1], 1, False),
                mock.call([node2, node3], 2, False)
            ],
        )
        cluster.nodes_by_zone.assert_has_calls(
            [mock.call('AZ5'), mock.call('AZ6')],
        )
Пример #7
0
    def test_select_candidates_random(self):
        self.spec['properties']['criteria'] = dp.DeletionPolicy.RANDOM
        policy = dp.DeletionPolicy('test-policy', self.spec)

        nodes = policy._select_candidates(self.context, self.cluster['id'], 1)
        self.assertEqual(1, len(nodes))
        nodes = policy._select_candidates(self.context, self.cluster['id'], 3)
        self.assertEqual(3, len(nodes))
        nodes = policy._select_candidates(self.context, self.cluster['id'], 10)
        self.assertEqual(6, len(nodes))
Пример #8
0
    def test_policy_init(self):
        policy = dp.DeletionPolicy('test-policy', self.spec)

        self.assertIsNone(policy.id)
        self.assertEqual('test-policy', policy.name)
        self.assertEqual('senlin.policy.deletion-1.0', policy.type)
        self.assertEqual('OLDEST_FIRST', policy.criteria)
        self.assertTrue(policy.destroy_after_deletion)
        self.assertEqual(60, policy.grace_period)
        self.assertFalse(policy.reduce_desired_capacity)
Пример #9
0
    def test_pre_op_node_delete(self, mock_update):
        action = mock.Mock()
        action.action = consts.NODE_DELETE
        action.context = self.context
        action.node.id = 'NODE_ID'
        action.inputs = {}
        action.data = {}

        policy = dp.DeletionPolicy('test-policy', self.spec)
        policy.pre_op('FAKE_ID', action)
        mock_update.assert_called_once_with(action, ['NODE_ID'])
Пример #10
0
    def test_pre_op_node_delete(self, mock_update):
        action = mock.Mock(action=consts.NODE_DELETE,
                           context=self.context,
                           inputs={},
                           data={},
                           entity=mock.Mock(id='NODE_ID'))
        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy.pre_op('FAKE_ID', action)

        mock_update.assert_called_once_with(action, ['NODE_ID'])
Пример #11
0
    def test_pre_op_del_nodes(self, mock_update):
        action = mock.Mock()
        action.context = self.context
        action.inputs = {
            'count': 2,
            'candidates': ['N1', 'N2'],
        }
        action.data = {}

        policy = dp.DeletionPolicy('test-policy', self.spec)
        policy.pre_op('FAKE_ID', action)
        mock_update.assert_called_once_with(action, ['N1', 'N2'])
Пример #12
0
    def test_select_candidates_youngest_first(self):
        self.spec['properties']['criteria'] = dp.DeletionPolicy.YOUNGEST_FIRST
        policy = dp.DeletionPolicy('test-policy', self.spec)

        nodes = policy._select_candidates(self.context, self.cluster['id'], 1)
        self.assertEqual(1, len(nodes))
        self.assertEqual(self.nodes_p2[2], nodes[0])

        nodes = policy._select_candidates(self.context, self.cluster['id'], 2)
        self.assertEqual(2, len(nodes))
        self.assertEqual(self.nodes_p2[2], nodes[0])
        self.assertEqual(self.nodes_p2[1], nodes[1])
Пример #13
0
    def test_pre_op_with_region_decisions(self, mock_select, mock_update):
        action = mock.Mock(context=self.context, inputs={})
        action.data = {'deletion': {'count': 2, 'regions': {'R1': 1, 'R2': 1}}}
        cluster = mock.Mock(nodes=['a', 'b', 'c'])
        action.entity = cluster
        mock_select.return_value = ['NODE1', 'NODE2']
        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy.pre_op('FAKE_ID', action)

        mock_update.assert_called_once_with(action, ['NODE1', 'NODE2'])
        mock_select.assert_called_once_with(cluster, {'R1': 1, 'R2': 1})
Пример #14
0
    def test_policy_init(self):
        policy = dp.DeletionPolicy('test-policy', self.spec)

        self.assertIsNone(policy.id)
        self.assertEqual('test-policy', policy.name)
        self.assertEqual('senlin.policy.deletion-1.0', policy.type)
        self.assertEqual(self.spec['properties']['criteria'], policy.criteria)
        self.assertEqual(self.spec['properties']['destroy_after_deletion'],
                         policy.destroy_after_deletion)
        self.assertEqual(self.spec['properties']['grace_period'],
                         policy.grace_period)
        self.assertEqual(self.spec['properties']['reduce_desired_capacity'],
                         policy.reduce_desired_capacity)
Пример #15
0
    def test_select_candidates_oldest_profile_first(self):
        criteria = dp.DeletionPolicy.OLDEST_PROFILE_FIRST
        self.spec['properties']['criteria'] = criteria
        policy = dp.DeletionPolicy('test-policy', self.spec)

        nodes = policy._select_candidates(self.context, self.cluster['id'], 1)
        self.assertEqual(1, len(nodes))
        self.assertEqual(self.nodes_p1[0], nodes[0])

        nodes = policy._select_candidates(self.context, self.cluster['id'], 2)
        self.assertEqual(2, len(nodes))
        self.assertEqual(self.nodes_p1[0], nodes[0])
        self.assertEqual(self.nodes_p1[1], nodes[1])
Пример #16
0
    def test_pre_op_resize_failed_parse(self, mock_parse, mock_update):
        action = mock.Mock(context=self.context,
                           inputs={},
                           data={},
                           action=consts.CLUSTER_RESIZE)
        cluster = mock.Mock(nodes=[mock.Mock(), mock.Mock()])
        action.entity = cluster
        mock_parse.return_value = 'ERROR', 'Failed parsing.'
        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy.pre_op('FAKE_ID', action)

        self.assertEqual('ERROR', action.data['status'])
        self.assertEqual('Failed parsing.', action.data['reason'])
        mock_parse.assert_called_once_with(action, cluster, 2)
        self.assertEqual(0, mock_update.call_count)
Пример #17
0
    def test_pre_op_scale_in_without_count(self, mock_select, mock_update):
        action = mock.Mock(context=self.context,
                           data={},
                           inputs={},
                           action=consts.CLUSTER_SCALE_IN)
        cluster = mock.Mock(nodes=[mock.Mock()])
        action.entity = cluster
        mock_select.return_value = ['NODE_ID']
        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy.pre_op('FAKE_ID', action)

        mock_update.assert_called_once_with(action, ['NODE_ID'])
        # the following was invoked with 1 because the input count is
        # not specified so 1 becomes the default
        mock_select.assert_called_once_with(cluster.nodes, 1, True)
Пример #18
0
    def test_select_candidates_error_nodes_first(self):
        kwargs = {
            'status': 'ERROR',
            'status_reason': 'Unknown',
        }

        self.nodes_p3 = self._create_nodes(self.cluster['id'],
                                           self.profile3['id'], 1, **kwargs)
        self.spec['properties']['criteria'] = \
            dp.DeletionPolicy.OLDEST_PROFILE_FIRST
        policy = dp.DeletionPolicy('test-policy', self.spec)

        nodes = policy._select_candidates(self.context, self.cluster['id'], 2)
        self.assertEqual(2, len(nodes))
        self.assertEqual(self.nodes_p3[0], nodes[0])
        self.assertEqual(self.nodes_p1[0], nodes[1])
        self._delete_nodes(self.nodes_p3[0])
Пример #19
0
    def test_pre_op_do_youngest_first(self, mock_select, mock_update):
        action = mock.Mock(context=self.context,
                           inputs={},
                           data={'deletion': {
                               'count': 2
                           }})
        cluster = mock.Mock(nodes=['a', 'b', 'c'])
        action.entity = cluster
        mock_select.return_value = ['NODE1', 'NODE2']
        spec = copy.deepcopy(self.spec)
        spec['properties']['criteria'] = 'YOUNGEST_FIRST'
        policy = dp.DeletionPolicy('test-policy', spec)

        policy.pre_op('FAKE_ID', action)

        mock_select.assert_called_once_with(cluster.nodes, 2, False)
        mock_update.assert_called_once_with(action, ['NODE1', 'NODE2'])
Пример #20
0
    def test_pre_op_do_oldest_first(self, mock_load, mock_select, mock_update):
        action = mock.Mock()
        action.context = self.context
        action.inputs = {}
        action.data = {'deletion': {'count': 2}}

        cluster = mock.Mock(nodes=['a', 'b', 'c'])
        mock_select.return_value = ['NODE1', 'NODE2']
        mock_load.return_value = cluster

        self.spec['properties']['criteria'] = 'OLDEST_FIRST'
        policy = dp.DeletionPolicy('test-policy', self.spec)
        policy.pre_op('FAKE_ID', action)

        mock_load.assert_called_once_with(action.context,
                                          cluster=None, cluster_id='FAKE_ID')
        mock_select.assert_called_once_with(cluster.nodes, 2, True)
        mock_update.assert_called_once_with(action, ['NODE1', 'NODE2'])
Пример #21
0
    def test_victims_by_regions_age_oldest(self, mock_select):
        cluster = mock.Mock()
        node1 = mock.Mock(id=1)
        node2 = mock.Mock(id=2)
        node3 = mock.Mock(id=3)
        cluster.nodes_by_region.side_effect = [[node1], [node2, node3]]

        mock_select.side_effect = [['1'], ['2', '3']]

        self.spec['properties']['criteria'] = 'OLDEST_FIRST'
        policy = dp.DeletionPolicy('test-policy', self.spec)

        res = policy._victims_by_regions(cluster, {'R1': 1, 'R2': 2})
        self.assertEqual(['1', '2', '3'], res)
        mock_select.assert_has_calls(
            [mock.call([node1], 1, True),
             mock.call([node2, node3], 2, True)])
        cluster.nodes_by_region.assert_has_calls(
            [mock.call('R1'), mock.call('R2')])
Пример #22
0
    def test_pre_op_resize_not_deletion(self, mock_parse, mock_update):
        def fake_parse(action, cluster, current):
            action.data = {}
            return 'OK', 'cool'

        action = mock.Mock(context=self.context,
                           inputs={},
                           action=consts.CLUSTER_RESIZE)
        cluster = mock.Mock(nodes=[mock.Mock(), mock.Mock()])
        action.entity = cluster
        mock_parse.side_effect = fake_parse
        policy = dp.DeletionPolicy('test-policy', self.spec)
        # a simulation of non-deletion RESZIE
        action.data = {}

        policy.pre_op('FAKE_ID', action)

        mock_parse.assert_called_once_with(action, cluster, 2)
        self.assertEqual(0, mock_update.call_count)
Пример #23
0
    def test_pre_op_resize_with_count(self, mock_select, mock_update,
                                      mock_parse):
        def fake_parse(a, cluster, current):
            a.data = {'deletion': {'count': 2}}
            return 'OK', 'cool'

        action = mock.Mock(context=self.context,
                           inputs={},
                           data={},
                           action=consts.CLUSTER_RESIZE)
        cluster = mock.Mock(nodes=[mock.Mock(), mock.Mock()])
        action.entity = cluster
        mock_parse.side_effect = fake_parse
        mock_select.return_value = ['NID']
        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy.pre_op('FAKE_ID', action)

        mock_parse.assert_called_once_with(action, cluster, 2)
        mock_update.assert_called_once_with(action, ['NID'])
Пример #24
0
    def test_pre_op_scale_in_with_count(self, mock_load, mock_select,
                                        mock_update):
        action = mock.Mock()
        action.action = consts.CLUSTER_SCALE_IN
        action.context = self.context
        action.data = {}
        action.inputs = {'count': 2}

        cluster = mock.Mock(nodes=[mock.Mock()])
        mock_load.return_value = cluster
        mock_select.return_value = ['NODE_ID']

        policy = dp.DeletionPolicy('test-policy', self.spec)
        policy.pre_op('FAKE_ID', action)

        mock_load.assert_called_once_with(action.context,
                                          cluster=None, cluster_id='FAKE_ID')
        mock_update.assert_called_once_with(action, ['NODE_ID'])
        # the following was invoked with 1 because the input count is
        # greater than the cluster size
        mock_select.assert_called_once_with(cluster.nodes, 1, True)
Пример #25
0
    def test_pre_op_resize_with_count(self, mock_get, mock_load,
                                      mock_select, mock_update,
                                      mock_parse):
        def fake_parse(a, obj):
            a.data = {
                'deletion': {
                    'count': 2
                }
            }
            return 'OK', 'cool'

        action = mock.Mock()
        action.context = self.context
        action.action = consts.CLUSTER_RESIZE
        action.inputs = {}
        action.data = {}

        db_cluster = mock.Mock()
        mock_get.return_value = db_cluster
        mock_parse.side_effect = fake_parse

        cluster = mock.Mock(nodes=[mock.Mock(), mock.Mock()])
        mock_load.return_value = cluster

        mock_select.return_value = ['NID']

        policy = dp.DeletionPolicy('test-policy', self.spec)

        # mock_parse = self.patchobject(su, 'parse_resize_params',
        #                              side_effect=fake_parse)

        policy.pre_op('FAKE_ID', action)

        mock_get.assert_called_once_with(action.context, 'FAKE_ID',
                                         project_safe=True)
        mock_parse.assert_called_once_with(action, db_cluster)
        mock_load.assert_called_once_with(action.context,
                                          cluster=db_cluster,
                                          cluster_id='FAKE_ID')
        mock_update.assert_called_once_with(action, ['NID'])
Пример #26
0
    def test_pre_op_resize_failed_parse(self, mock_get, mock_parse,
                                        mock_update):
        action = mock.Mock()
        action.context = self.context
        action.action = consts.CLUSTER_RESIZE
        action.inputs = {}
        action.data = {}

        db_cluster = mock.Mock()
        mock_get.return_value = db_cluster
        mock_parse.return_value = 'ERROR', 'Failed parsing.'

        policy = dp.DeletionPolicy('test-policy', self.spec)

        policy.pre_op('FAKE_ID', action)

        self.assertEqual('ERROR', action.data['status'])
        self.assertEqual('Failed parsing.', action.data['reason'])
        mock_get.assert_called_once_with(action.context, 'FAKE_ID',
                                         project_safe=True)
        mock_parse.assert_called_once_with(action, db_cluster)
        self.assertEqual(0, mock_update.call_count)
Пример #27
0
    def test_pre_op(self, mock_cluster, mock_parse):
        action = mock.Mock()
        action.context = self.context
        action.inputs = {}
        policy = dp.DeletionPolicy('test-policy', self.spec)
        mock_parse.return_value = 'OK', ''

        # CLUSTER_SCALE_IN or ClUSTER_DEL_NODES action
        # action data doesn't have 'deletion' field
        action.data = {}
        action.action = consts.CLUSTER_SCALE_IN
        policy.pre_op(self.cluster['id'], action)
        pd = {
            'status': 'OK',
            'reason': 'Candidates generated',
            'deletion': {
                'candidates': [self.nodes_p1[0]],
                'destroy_after_deletion': True,
                'grace_period': 60,
            }
        }
        self.assertEqual(pd, action.data)

        # action data has 'deletion' field, but 'count' is not provided
        action.data = {'abc': 123}
        action.action = consts.CLUSTER_DEL_NODES
        policy.pre_op(self.cluster['id'], action)
        pd = {
            'status': 'OK',
            'reason': 'Candidates generated',
            'deletion': {
                'candidates': [self.nodes_p1[0]],
                'destroy_after_deletion': True,
                'grace_period': 60,
            },
            'abc': 123
        }
        self.assertEqual(pd, action.data)

        # 'count' is provided in inputs field of action
        action.inputs = {'count': 2}
        action.action = consts.CLUSTER_DEL_NODES
        action.data = {}
        policy.pre_op(self.cluster['id'], action)
        pd = {
            'status': 'OK',
            'reason': 'Candidates generated',
            'deletion': {
                'candidates': [self.nodes_p1[0], self.nodes_p1[1]],
                'destroy_after_deletion': True,
                'grace_period': 60,
            }
        }
        self.assertEqual(pd, action.data)
        action.store.assert_called_with(self.context)
        # CLUSTER_RESIZE action
        # delete nodes
        action.action = consts.CLUSTER_RESIZE
        action.data = {'deletion': {'count': 1}}
        policy.pre_op(self.cluster['id'], action)
        pd = {
            'status': 'OK',
            'reason': 'Candidates generated',
            'deletion': {
                'candidates': [self.nodes_p1[0]],
                'destroy_after_deletion': True,
                'grace_period': 60,
                'count': 1,
            }
        }
        self.assertEqual(pd, action.data)
        action.store.assert_called_with(self.context)