API and engine support for receiver notifying
This patch adds basic support for receiver notifying in API and engine service layers. Change-Id: Iddf561a3d94014abd80fabe5f8f482acc9c74661
This commit is contained in:
parent
654487f86c
commit
7edb329c16
|
@ -41,6 +41,7 @@
|
|||
"receivers:create": "",
|
||||
"receivers:get": "",
|
||||
"receivers:delete": "",
|
||||
"receivers:notify": "",
|
||||
"actions:index": "",
|
||||
"actions:get": "",
|
||||
"events:index": "",
|
||||
|
|
|
@ -133,3 +133,8 @@ class ReceiverController(wsgi.Controller):
|
|||
def delete(self, req, receiver_id):
|
||||
self.rpc_client.receiver_delete(req.context, receiver_id, cast=False)
|
||||
raise exc.HTTPNoContent()
|
||||
|
||||
@util.policy_enforce
|
||||
def notify(self, req, receiver_id, body=None):
|
||||
self.rpc_client.receiver_notify(req.context, receiver_id, body)
|
||||
raise exc.HTTPNoContent()
|
||||
|
|
|
@ -254,6 +254,10 @@ class API(wsgi.Router):
|
|||
"/receivers/{receiver_id}",
|
||||
action="delete",
|
||||
conditions={'method': 'DELETE'})
|
||||
sub_mapper.connect("receiver_notify",
|
||||
"/receivers/{receiver_id}/notify",
|
||||
action="notify",
|
||||
conditions={'method': 'POST'})
|
||||
|
||||
# Webhooks
|
||||
res = wsgi.Resource(webhooks.WebhookController(conf))
|
||||
|
|
|
@ -2197,6 +2197,26 @@ class EngineService(service.Service):
|
|||
receiver_mod.Receiver.delete(context, db_receiver.id)
|
||||
LOG.info(_LI("Receiver %s is deleted."), identity)
|
||||
|
||||
@request_context
|
||||
def receiver_notify(self, context, identity, params=None):
|
||||
"""Handle notification to specified receiver.
|
||||
|
||||
:param context: An instance of the request context.
|
||||
:param identity: The UUID, name or short-id of a receiver.
|
||||
:param params: Parameters received from notification.
|
||||
"""
|
||||
db_receiver = self.receiver_find(context, identity)
|
||||
# permission checking
|
||||
if not context.is_admin and context.user != db_receiver.user:
|
||||
raise exception.Forbidden()
|
||||
|
||||
# Receiver type check
|
||||
if db_receiver.type != consts.RECEIVER_MESSAGE:
|
||||
raise exception.Forbidden()
|
||||
|
||||
# TODO(Yanyanhu): add notification handling logic
|
||||
LOG.info(_LI("Received notification to receiver %s."), identity)
|
||||
|
||||
@request_context
|
||||
def webhook_trigger(self, context, identity, params=None):
|
||||
|
||||
|
|
|
@ -338,6 +338,11 @@ class EngineClient(object):
|
|||
return rpc_method(ctxt, self.make_msg('receiver_delete',
|
||||
identity=identity))
|
||||
|
||||
def receiver_notify(self, ctxt, identity, params=None):
|
||||
return self.call(ctxt,
|
||||
self.make_msg('receiver_notify', identity=identity,
|
||||
params=params))
|
||||
|
||||
def webhook_trigger(self, ctxt, identity, params=None):
|
||||
return self.call(ctxt,
|
||||
self.make_msg('webhook_trigger', identity=identity,
|
||||
|
|
|
@ -533,3 +533,36 @@ class ReceiverControllerTest(shared.ControllerTest, base.SenlinTestCase):
|
|||
|
||||
self.assertEqual(403, resp.status_int)
|
||||
self.assertIn('403 Forbidden', six.text_type(resp))
|
||||
|
||||
def test_receiver_notify_success(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'notify')
|
||||
wid = 'aaaa-bbbb-cccc'
|
||||
req = self._post('/receivers/%(receiver_id)s/notify' % {
|
||||
'receiver_id': wid}, None)
|
||||
|
||||
mock_call = self.patchobject(rpc_client.EngineClient, 'call',
|
||||
return_value=None)
|
||||
|
||||
self.assertRaises(exc.HTTPNoContent,
|
||||
self.controller.notify, req, receiver_id=wid)
|
||||
|
||||
mock_call.assert_called_with(
|
||||
req.context,
|
||||
('receiver_notify', {'identity': wid, 'params': None}))
|
||||
|
||||
def test_receiver_notify_not_found(self, mock_enforce):
|
||||
self._mock_enforce_setup(mock_enforce, 'notify')
|
||||
wid = 'aaaa-bbbb-cccc'
|
||||
req = self._post('/receivers/%(receiver_id)s/notify' % {
|
||||
'receiver_id': wid}, None)
|
||||
|
||||
error = senlin_exc.ResourceNotFound(type='receiver', id=wid)
|
||||
mock_call = self.patchobject(rpc_client.EngineClient, 'call')
|
||||
mock_call.side_effect = shared.to_remote_error(error)
|
||||
|
||||
resp = shared.request_with_middleware(fault.FaultWrapper,
|
||||
self.controller.notify,
|
||||
req, receiver_id=wid)
|
||||
|
||||
self.assertEqual(404, resp.json['code'])
|
||||
self.assertEqual('ResourceNotFound', resp.json['error']['type'])
|
||||
|
|
|
@ -399,6 +399,16 @@ class RoutesTest(base.SenlinTestCase):
|
|||
'receiver_id': 'bbbb'
|
||||
})
|
||||
|
||||
self.assertRoute(
|
||||
self.m,
|
||||
'/receivers/bbbb/notify',
|
||||
'POST',
|
||||
'notify',
|
||||
'ReceiverController',
|
||||
{
|
||||
'receiver_id': 'bbbb'
|
||||
})
|
||||
|
||||
def test_webhook_collection(self):
|
||||
self.assertRoute(
|
||||
self.m,
|
||||
|
|
|
@ -94,7 +94,7 @@ class ControllerTest(object):
|
|||
self.context = req.context
|
||||
ver = version if version else wsgi.DEFAULT_API_VERSION
|
||||
req.version_request = vr.APIVersionRequest(ver)
|
||||
req.body = encodeutils.safe_encode(data)
|
||||
req.body = encodeutils.safe_encode(data) if data else None
|
||||
return req
|
||||
|
||||
def _post(self, path, data, content_type='application/json', version=None):
|
||||
|
|
|
@ -370,3 +370,47 @@ class ReceiverTest(base.SenlinTestCase):
|
|||
ex = self.assertRaises(rpc.ExpectedException,
|
||||
self.eng.receiver_delete, self.ctx, 'Bogus')
|
||||
self.assertEqual(exc.ResourceNotFound, ex.exc_info[0])
|
||||
|
||||
@mock.patch.object(service.EngineService, 'receiver_find')
|
||||
def test_receiver_notify(self, mock_find):
|
||||
fake_obj = mock.Mock()
|
||||
fake_obj.id = 'FAKE_ID'
|
||||
fake_obj.type = 'message'
|
||||
fake_obj.user = self.ctx.user
|
||||
mock_find.return_value = fake_obj
|
||||
|
||||
result = self.eng.receiver_notify(self.ctx, 'FAKE_RECEIVER')
|
||||
|
||||
self.assertIsNone(result)
|
||||
mock_find.assert_called_once_with(self.ctx, 'FAKE_RECEIVER')
|
||||
|
||||
@mock.patch.object(service.EngineService, 'receiver_find')
|
||||
def test_receiver_notify_not_found(self, mock_find):
|
||||
mock_find.side_effect = exc.ResourceNotFound(type='receiver', id='RR')
|
||||
|
||||
ex = self.assertRaises(rpc.ExpectedException,
|
||||
self.eng.receiver_notify, self.ctx, 'Bogus')
|
||||
self.assertEqual(exc.ResourceNotFound, ex.exc_info[0])
|
||||
|
||||
@mock.patch.object(service.EngineService, 'receiver_find')
|
||||
def test_receiver_notify_permission_check_fail(self, mock_find):
|
||||
fake_obj = mock.Mock()
|
||||
fake_obj.id = 'FAKE_ID'
|
||||
fake_obj.user = 'foo'
|
||||
mock_find.return_value = fake_obj
|
||||
|
||||
ex = self.assertRaises(rpc.ExpectedException,
|
||||
self.eng.receiver_notify, self.ctx, 'Bogus')
|
||||
self.assertEqual(exc.Forbidden, ex.exc_info[0])
|
||||
|
||||
@mock.patch.object(service.EngineService, 'receiver_find')
|
||||
def test_receiver_notify_incorrect_type(self, mock_find):
|
||||
fake_obj = mock.Mock()
|
||||
fake_obj.id = 'FAKE_ID'
|
||||
fake_obj.user = self.ctx.user
|
||||
fake_obj.type = 'not_message'
|
||||
mock_find.return_value = fake_obj
|
||||
|
||||
ex = self.assertRaises(rpc.ExpectedException,
|
||||
self.eng.receiver_notify, self.ctx, 'Bogus')
|
||||
self.assertEqual(exc.Forbidden, ex.exc_info[0])
|
||||
|
|
Loading…
Reference in New Issue