def view_manifest(self): """ see :meth:`otter.models.interface.IScalingGroup.view_manifest` """ def _get_policies(group): """ Now that we know the group exists, get its policies """ d = self._naive_list_policies() d.addCallback( lambda policies: { 'groupConfiguration': _jsonloads_data(group['group_config'] ), 'launchConfiguration': _jsonloads_data(group[ 'launch_config']), 'scalingPolicies': policies, 'id': self.uuid }) return d view_query = _cql_view_manifest.format(cf=self.group_table) del_query = _cql_delete_all_in_group.format(cf=self.group_table) d = verified_view(self.connection, view_query, del_query, { "tenantId": self.tenant_id, "groupId": self.uuid }, get_consistency_level('view', 'group'), NoSuchScalingGroupError(self.tenant_id, self.uuid), self.log) return d.addCallback(_get_policies)
def test_update_group_config_404(self): """ If you try to modify a not-found object it fails with a 404 not found """ self.mock_group.update_config.return_value = defer.fail( NoSuchScalingGroupError('11111', 'one')) request_body = { 'name': 'blah', 'cooldown': 60, 'minEntities': 0, 'maxEntities': 25, 'metadata': {} } expected_config = { 'name': 'blah', 'cooldown': 60, 'minEntities': 0, 'maxEntities': 25, 'metadata': {} } response_body = self.assert_status_code(404, method='PUT', body=json.dumps(request_body)) resp = json.loads(response_body) self.mock_group.update_config.assert_called_once_with(expected_config) self.assertEqual(resp['type'], 'NoSuchScalingGroupError') self.flushLoggedErrors(NoSuchScalingGroupError)
def test_exe_wbhk_logs_info_message_when_policy_cannot_be_executed( self, blk, log): """ Executing a webhook logs an information message about non-fatal, policy execution failures. """ cap_log = log.bind.return_value.bind.return_value exceptions = [ CannotExecutePolicyError('tenant', 'group', 'policy', 'test'), NoSuchPolicyError('tenant', 'group', 'policy'), NoSuchScalingGroupError('tenant', 'group'), UnrecognizedCapabilityError("11111", 1) ] for exc in exceptions: self.mock_store.webhook_info_by_hash.return_value = defer.succeed( ('tenant', 'group', 'policy')) self.mock_controller.modify_and_trigger.side_effect = \ lambda *args, **kwargs: defer.fail(exc) self.assert_status_code(202, '/v1.0/execute/1/11111/', 'POST') cap_log.bind().msg.assert_any_call( 'Non-fatal error during webhook execution: {exc!r}', exc=exc) self.assertEqual(0, cap_log.err.call_count) self.assertEqual(0, cap_log.bind().err.call_count)
def test_update_webhook_for_unknowns_is_404(self): """ When updating a webhook, endpoint returns a 404 if: - the group doesn't exist and :class:`NoSuchScalingGroupError` is raised - the policy doesn't exist and :class:`NoSuchPolicyError` is raised - the webhook doesn't exist and :class:`NoSuchWebhookError` is raised """ errors = [ NoSuchScalingGroupError(self.tenant_id, self.group_id), NoSuchPolicyError(self.tenant_id, self.group_id, self.policy_id), NoSuchWebhookError(self.tenant_id, self.group_id, self.policy_id, self.webhook_id) ] for error in errors: self.mock_group.update_webhook.return_value = defer.fail(error) self.assert_status_code( 404, None, 'PUT', json.dumps({ 'name': 'one', 'metadata': {} })) self.mock_group.update_webhook.assert_called_once_with( self.policy_id, self.webhook_id, { 'name': 'one', 'metadata': {} }) self.flushLoggedErrors(type(error)) self.mock_group.update_webhook.reset_mock()
def _mock_modify_state(modifier, *args, **kwargs): index = events_indexes.pop(0) if index == 0: return defer.fail(NoSuchPolicyError('1234', 'scal44', 'pol44')) if index == 1: return defer.fail(NoSuchScalingGroupError('1234', 'scal44')) modifier(self.mock_group, self.mock_state, *args, **kwargs) return defer.succeed(None)
def test_group_deleted(self): """ Does nothing if group has been deleted """ seq = [(GetScalingGroupInfo(tenant_id="tid", group_id="gid"), lambda i: raise_(NoSuchScalingGroupError("tid", "gid"))), (Log("selfheal-group-deleted", dict(tenant_id="tid", scaling_group_id="gid")), noop)] self.assertIsNone( perform_sequence(seq, sh.check_and_trigger("tid", "gid")))
def test_modify_state_propagates_view_state_error(self): """ ``modify_state`` should propagate a :class:`NoSuchScalingGroupError` that is raised by ``view_state`` """ self.group.view_state = mock.Mock( return_value=defer.fail(NoSuchScalingGroupError(1, 1))) modifier = mock.Mock() d = self.group.modify_state(modifier) f = self.failureResultOf(d) self.assertTrue(f.check(NoSuchScalingGroupError)) self.assertEqual(modifier.call_count, 0)
def test_get_group_config_404(self): """ If the group does not exist, an attempt to get the config returns a 404 """ self.mock_group.view_config.return_value = defer.fail( NoSuchScalingGroupError('11111', '1')) response_body = self.assert_status_code(404) resp = json.loads(response_body) self.mock_store.get_scaling_group.assert_called_once_with( mock.ANY, '11111', '1') self.mock_group.view_config.assert_called_once_with() self.assertEqual(resp['type'], 'NoSuchScalingGroupError') self.flushLoggedErrors(NoSuchScalingGroupError)
def view_state(self): """ see :meth:`otter.models.interface.IScalingGroup.view_state` """ view_query = _cql_view_group_state.format(cf=self.group_table) del_query = _cql_delete_all_in_group.format(cf=self.group_table) d = verified_view(self.connection, view_query, del_query, { "tenantId": self.tenant_id, "groupId": self.uuid }, get_consistency_level('view', 'partial'), NoSuchScalingGroupError(self.tenant_id, self.uuid), self.log) return d.addCallback(_unmarshal_state)
def test_deleted_group_event(self): """This event's group has been deleted. Its policyId is logged, and no attempt is made to execute it. """ del_pol_ids = set() self.mock_mt.side_effect = \ lambda *_, **__: defer.fail(NoSuchScalingGroupError(1, 2)) d = execute_event("disp", self.mock_store, self.log, self.event, del_pol_ids) self.assertIsNone(self.successResultOf(d)) self.assertEqual(del_pol_ids, set(['pol44'])) self.assertFalse(self.maybe_exec_policy.called)
def test_view_state_404(self): """ Viewing the state of a non-existant group fails with a 404. """ self.mock_group.view_state.return_value = defer.fail( NoSuchScalingGroupError('11111', 'one')) response_body = self.assert_status_code(404, method="GET") self.mock_store.get_scaling_group.assert_called_once_with( mock.ANY, '11111', 'one') self.mock_group.view_state.assert_called_once_with() resp = json.loads(response_body) self.assertEqual(resp['type'], 'NoSuchScalingGroupError') self.flushLoggedErrors(NoSuchScalingGroupError)
def view_launch_config(self): """ see :meth:`otter.models.interface.IScalingGroup.view_launch_config` """ view_query = _cql_view.format(cf=self.group_table, column='launch_config') del_query = _cql_delete_all_in_group.format(cf=self.group_table) d = verified_view(self.connection, view_query, del_query, { "tenantId": self.tenant_id, "groupId": self.uuid }, get_consistency_level('view', 'partial'), NoSuchScalingGroupError(self.tenant_id, self.uuid), self.log) return d.addCallback( lambda group: _jsonloads_data(group['launch_config']))
def test_update_group_config_404(self): """ If you try to modify a not-found object it fails with a 404 not found """ self.mock_group.update_launch_config.return_value = defer.fail( NoSuchScalingGroupError('11111', 'one')) response_body = self.assert_status_code(404, method='PUT', body=json.dumps( launch_examples()[0])) resp = json.loads(response_body) self.mock_group.update_launch_config.assert_called_once_with( launch_examples()[0]) self.assertEqual(resp['type'], 'NoSuchScalingGroupError') self.flushLoggedErrors(NoSuchScalingGroupError)
def test_list_webhooks_for_unknowns_is_404(self): """ When listing webhooks, endpoint returns 404 if: - the group doesn't exist, :class:`NoSuchScalingGroupError` is raised - the policy doesn't exist, :class:`NoSuchPolicyError` is raised """ errors = [ NoSuchScalingGroupError(self.tenant_id, self.group_id), NoSuchPolicyError(self.tenant_id, self.group_id, self.policy_id) ] for error in errors: self.mock_group.list_webhooks.return_value = defer.fail(error) self.assert_status_code(404) self.mock_group.list_webhooks.assert_called_once_with( self.policy_id, limit=100) self.flushLoggedErrors(type(error)) self.mock_group.list_webhooks.reset_mock()
def __init__(self, log, tenant_id, uuid, collection, creation=None): """ Creates a MockScalingGroup object. If the actual scaling group should be created, a creation argument is provided containing the config, the launch config, and optional scaling policies. """ self.log = log.bind(system=self.__class__.__name__) self.tenant_id = tenant_id self.uuid = uuid self.state = GroupState(self.tenant_id, self.uuid, {}, {}, None, {}, False) self._collection = collection if creation is not None: self.error = None self.config = { 'name': "", 'cooldown': 0, 'minEntities': 0, 'maxEntities': None, # no upper limit 'metadata': {} } self.update_config(creation['config'], partial_update=True) self.launch = creation['launch'] self.policies = {} if creation['policies']: self.create_policies(creation['policies']) self.webhooks = defaultdict(dict) else: self.error = NoSuchScalingGroupError(tenant_id, uuid) self.config = None self.launch = None self.policies = None self.webhooks = None