diff --git a/monasca/common/repositories/exceptions.py b/monasca/common/repositories/exceptions.py index 30f42c552..62a49d898 100644 --- a/monasca/common/repositories/exceptions.py +++ b/monasca/common/repositories/exceptions.py @@ -19,3 +19,7 @@ class RepositoryException(Exception): class DoesNotExistException(RepositoryException): pass + + +class AlreadyExistsException(RepositoryException): + pass diff --git a/monasca/common/repositories/mysql/notifications_repository.py b/monasca/common/repositories/mysql/notifications_repository.py index e83615002..f8e5a9ab1 100644 --- a/monasca/common/repositories/mysql/notifications_repository.py +++ b/monasca/common/repositories/mysql/notifications_repository.py @@ -14,120 +14,148 @@ import datetime -import model -import peewee - from monasca.common.repositories import exceptions -from monasca.common.repositories import notifications_repository +from monasca.common.repositories.mysql import mysql_repository +from monasca.common.repositories import notifications_repository as nr from monasca.openstack.common import log +from monasca.openstack.common import uuidutils LOG = log.getLogger(__name__) -class Notification_Method(model.Model): - id = peewee.TextField(36) - tenant_id = peewee.TextField(36) - name = peewee.TextField() - type = peewee.TextField() - address = peewee.TextField() - created_at = peewee.DateTimeField() - updated_at = peewee.DateTimeField() +class NotificationsRepository(mysql_repository.MySQLRepository, + nr.NotificationsRepository): + def __init__(self): -class NotificationsRepository( - notifications_repository.NotificationsRepository): + super(NotificationsRepository, self).__init__() - def notification_from_result(self, result): - notification = dict(id=result.id, - name=result.name, - type=result.type, - address=result.address) - return notification + def create_notification(self, tenant_id, name, + notification_type, address): - def exists(self, tenant_id, name): - try: - return (Notification_Method.select().where( - (Notification_Method.tenant_id == tenant_id) & ( - Notification_Method.name == name)).count() > 0) - except Exception as ex: - LOG.exception(ex) - raise exceptions.RepositoryException(ex) + cnxn, cursor = self._get_cnxn_cursor_tuple() + + with cnxn: + + query = """ + select * + from notification_method + where tenant_id = %s and name = %s""" + + parms = [tenant_id, name.encode('utf8')] + + cursor.execute(query, parms) + + if cursor.rowcount > 0: + raise exceptions.AlreadyExistsException('Notification already ' + 'exists') - def create_notification( - self, id, tenant_id, name, notification_type, address): - try: now = datetime.datetime.utcnow() - Notification_Method.create( - id=id, - tenant_id=tenant_id, - name=name, - notification_type=notification_type, - address=address, - created_at=now, - updated_at=now) - except Exception as ex: - LOG.exception(ex) - raise exceptions.RepositoryException(ex) + notification_id = uuidutils.generate_uuid() + query = """ + insert into notification_method( + id, + tenant_id, + name, + type, + address, + created_at, + updated_at + ) values (%s, %s, %s, % s, %s, %s, %s)""" + parms = [notification_id, + tenant_id, + name.encode('utf8'), + notification_type.encode('utf8'), + address.encode('utf8'), + now, + now] + + cursor.execute(query, parms) + + return notification_id + + @mysql_repository.mysql_try_catch_block def list_notifications(self, tenant_id): - try: - q = Notification_Method.select().where( - Notification_Method.tenant_id == tenant_id) - results = q.execute() - notifications = [ - self.notification_from_result(result) for result in results] - return notifications - except Exception as ex: - LOG.exception(ex) - raise exceptions.RepositoryException(ex) + query = """ + select * + from notification_method + where tenant_id = %s""" - def delete_notification(self, tenant_id, notification_id): + parms = [tenant_id] - try: - q = Notification_Method.delete().where( - (Notification_Method.tenant_id == tenant_id) & ( - Notification_Method.id == notification_id)) - num_rows_deleted = q.execute() - except Exception as ex: - LOG.exception(ex) - raise exceptions.RepositoryException(ex) + rows = self._execute_query(query, parms) - if num_rows_deleted < 1: - raise exceptions.DoesNotExistException() + return rows - return + @mysql_repository.mysql_try_catch_block + def delete_notification(self, tenant_id, id): + cnxn, cursor = self._get_cnxn_cursor_tuple() + + with cnxn: + + query = """ + select * + from notification_method + where tenant_id = %s and id = %s""" + + parms = [tenant_id, id] + + cursor.execute(query, parms) + + if cursor.rowcount < 1: + raise exceptions.DoesNotExistException + + query = """ + delete + from notification_method + where tenant_id = %s and id = %s""" + + cursor.execute(query, parms) + + @mysql_repository.mysql_try_catch_block def list_notification(self, tenant_id, notification_id): - try: - result = Notification_Method.get( - (Notification_Method.tenant_id == tenant_id) & ( - Notification_Method.id == notification_id)) - return (self.notification_from_result(result)) - except Notification_Method.DoesNotExist as e: - raise exceptions.DoesNotExistException(str(e)) - except Exception as ex: - LOG.exception(ex) - raise exceptions.RepositoryException(ex) - def update_notification( - self, id, tenant_id, name, notification_type, address): - now = datetime.datetime.utcnow() - try: - q = Notification_Method.update( - name=name, - type=notification_type, - address=address, - created_at=now, - updated_at=now).where( - (Notification_Method.tenant_id == tenant_id) & ( - Notification_Method.id == id)) - # Execute the query, updating the database. - num_rows_updated = q.execute() - except Exception as ex: - LOG.exception(ex) - raise exceptions.RepositoryException(ex) + parms = [tenant_id, notification_id] + + query = """ + select * + from notification_method + where tenant_id = %s and id = %s""" + + rows = self._execute_query(query, parms) + + if rows: + return rows[0] else: - if num_rows_updated == 0: + raise exceptions.DoesNotExistException + + @mysql_repository.mysql_try_catch_block + def update_notification( + self, id, tenant_id, name, type, address): + + cnxn, cursor = self._get_cnxn_cursor_tuple() + + with cnxn: + + now = datetime.datetime.utcnow() + + query = """ + update notification_method + set name = %s, + type = %s, + address = %s, + created_at = %s, + updated_at = %s + where tenant_id = %s and id = %s""" + + parms = [name.encode('utf8'), type.encode('utf8'), address.encode( + 'utf8'), now, now, tenant_id, id] + + cursor.execute(query, parms) + + if cursor.rowcount < 1: raise exceptions.DoesNotExistException('Not Found') diff --git a/monasca/v2/reference/notifications.py b/monasca/v2/reference/notifications.py index 409b97132..1264b2338 100644 --- a/monasca/v2/reference/notifications.py +++ b/monasca/v2/reference/notifications.py @@ -18,21 +18,24 @@ import falcon from oslo.config import cfg from monasca.api import monasca_notifications_api_v2 -from monasca.common.repositories import exceptions as repository_exceptions from monasca.common import resource_api from monasca.openstack.common import log -from monasca.openstack.common import uuidutils from monasca.v2.common.schemas import (exceptions as schemas_exceptions) from monasca.v2.common.schemas import ( notifications_request_body_schema as schemas_notifications) from monasca.v2.reference import helpers +from monasca.v2.reference.resource import resource_try_catch_block + LOG = log.getLogger(__name__) class Notifications(monasca_notifications_api_v2.NotificationsV2API): + def __init__(self, global_conf): + super(Notifications, self).__init__(global_conf) + self._region = cfg.CONF.region self._default_authorized_roles = ( cfg.CONF.security.default_authorized_roles) @@ -51,111 +54,83 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API): LOG.debug(ex) raise falcon.HTTPBadRequest('Bad request', ex.message) - def _create_notification(self, id, tenant_id, notification): - """Store the notification using the repository. + @resource_try_catch_block + def _create_notification(self, tenant_id, notification, uri): - :param notification: A notification object. - :raises: falcon.HTTPServiceUnavailable,falcon.HTTPConflict - """ - try: - name = notification['name'] - notification_type = notification['type'].upper() - address = notification['address'] - if self._notifications_repo.exists(tenant_id, name): - raise falcon.HTTPConflict('Conflict', ( - 'Notification Method already exists: tenant_id=%s ' - 'name=%s' % ( - tenant_id, name)), code=409) - self._notifications_repo.create_notification(id, tenant_id, name, - notification_type, - address) - except repository_exceptions.RepositoryException as ex: - LOG.error(ex) - raise falcon.HTTPInternalServerError('Service unavailable', - ex.message) + name = notification['name'].decode('utf8') + notification_type = notification['type'].upper().decode('utf8') + address = notification['address'].decode('utf8') + notification_id = self._notifications_repo.create_notification( + tenant_id, + name, + notification_type, + address) - def _update_notification(self, id, tenant_id, notification): - """Update the notification using the repository. + return self._create_notification_response(notification_id, + name, + notification_type, + address, + uri) - :param notification: A notification object. - :raises: falcon.HTTPServiceUnavailable,falcon.HTTPError (404) - """ - try: - name = notification['name'] - notification_type = notification['type'].upper() - address = notification['address'] - self._notifications_repo.update_notification(id, tenant_id, name, - notification_type, - address) - except repository_exceptions.DoesNotExistException: - helpers.raise_not_found_exception('notification', id, tenant_id) - except repository_exceptions.RepositoryException as ex: - LOG.error(ex) - raise falcon.HTTPInternalServerError('Service unavailable', - ex.message) + @resource_try_catch_block + def _update_notification(self, id, tenant_id, notification, uri): - def _create_notification_response(self, id, notification, uri): - name = notification['name'] - notification_type = notification['type'].upper() - address = notification['address'] - response = {'id': id, 'name': name, 'type': notification_type, + name = notification['name'].decode('utf8') + notification_type = notification['type'].upper().decode('utf8') + address = notification['address'].decode('utf8') + self._notifications_repo.update_notification(id, tenant_id, name, + notification_type, + address) + + return self._create_notification_response(id, + name, + notification_type, + address, + uri) + + def _create_notification_response(self, id, name, type, + address, uri): + + response = {'id': id, 'name': name, 'type': type, 'address': address} - return json.dumps(helpers.add_links_to_resource(response, uri), - ensure_ascii=False).encode('utf8') + return helpers.add_links_to_resource(response, uri) + + @resource_try_catch_block def _list_notifications(self, tenant_id, uri): - """Lists all notifications for this tenant id. - :param tenant_id: The tenant id. - :raises: falcon.HTTPServiceUnavailable - """ - try: - notifications = self._notifications_repo.list_notifications( - tenant_id) - return json.dumps( - helpers.add_links_to_resource_list(notifications, uri)) - except repository_exceptions.RepositoryException as ex: - LOG.error(ex) - raise falcon.HTTPInternalServerError('Service unavailable', - ex.message) + rows = self._notifications_repo.list_notifications(tenant_id) + return [self._build_notification_result(row, + uri) for row in rows] + + @resource_try_catch_block def _list_notification(self, tenant_id, notification_id, uri): - """Lists the notification by id. - :param tenant_id: The tenant id. - :param notification_id: The notification id - :raises: falcon.HTTPServiceUnavailable,falcon.HTTPError (404): - """ - try: - notifications = self._notifications_repo.list_notification( - tenant_id, notification_id) - return json.dumps( - helpers.add_links_to_resource(notifications, uri)) - except repository_exceptions.DoesNotExistException: - helpers.raise_not_found_exception('notification', notification_id, - tenant_id) - except repository_exceptions.RepositoryException as ex: - LOG.error(ex) - raise falcon.HTTPInternalServerError('Service unavailable', - ex.message) + row = self._notifications_repo.list_notification( + tenant_id, + notification_id) + return self._build_notification_result(row, uri) + + def _build_notification_result(self, notification_row, uri): + + result = { + u'id': notification_row['id'], + u'name': notification_row['name'], + u'type': notification_row['type'], + u'address': notification_row['address'] + } + + helpers.add_links_to_resource(result, uri) + + return result + + @resource_try_catch_block def _delete_notification(self, tenant_id, notification_id): - """Deletes the notification using the repository. - :param tenant_id: The tenant id. - :param notification_id: The notification id - :raises: falcon.HTTPServiceUnavailable,falcon.HTTPError (404) - """ - try: - self._notifications_repo.delete_notification(tenant_id, - notification_id) - except repository_exceptions.DoesNotExistException: - helpers.raise_not_found_exception('notification', notification_id, - tenant_id) - except repository_exceptions.RepositoryException as ex: - LOG.error(ex) - raise falcon.HTTPInternalServerError('Service unavailable', - ex.message) + self._notifications_repo.delete_notification(tenant_id, + notification_id) @resource_api.Restify('/v2.0/notification-methods', method='post') def do_post_notification_methods(self, req, res): @@ -163,18 +138,17 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API): helpers.validate_authorization(req, self._default_authorized_roles) notification = helpers.read_http_resource(req) self._validate_notification(notification) - id = uuidutils.generate_uuid() tenant_id = helpers.get_tenant_id(req) - self._create_notification(id, tenant_id, notification) - res.body = self._create_notification_response(id, notification, - req.uri) - res.status = falcon.HTTP_200 + result = self._create_notification(tenant_id, notification, req.uri) + res.body = json.dumps(result, ensure_ascii=False).encode('utf8') + res.status = falcon.HTTP_201 @resource_api.Restify('/v2.0/notification-methods', method='get') def do_get_notification_methods(self, req, res): helpers.validate_authorization(req, self._default_authorized_roles) tenant_id = helpers.get_tenant_id(req) - res.body = self._list_notifications(tenant_id, req.uri) + result = self._list_notifications(tenant_id, req.uri) + res.body = json.dumps(result, ensure_ascii=False).encode('utf8') res.status = falcon.HTTP_200 @resource_api.Restify('/v2.0/notification-methods/{id}', method='delete') @@ -188,7 +162,8 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API): def do_get_notification_method(self, req, res, id): helpers.validate_authorization(req, self._default_authorized_roles) tenant_id = helpers.get_tenant_id(req) - res.body = self._list_notification(tenant_id, id, req.uri) + result = self._list_notification(tenant_id, id, req.uri) + res.body = json.dumps(result, ensure_ascii=False).encode('utf8') res.status = falcon.HTTP_200 @resource_api.Restify('/v2.0/notification-methods/{id}', method='put') @@ -198,7 +173,7 @@ class Notifications(monasca_notifications_api_v2.NotificationsV2API): notification = helpers.read_http_resource(req) self._validate_notification(notification) tenant_id = helpers.get_tenant_id(req) - self._update_notification(id, tenant_id, notification) - res.body = self._create_notification_response(id, notification, - req.uri) + result = self._update_notification(id, tenant_id, notification, + req.uri) + res.body = json.dumps(result, ensure_ascii=False).encode('utf8') res.status = falcon.HTTP_200 diff --git a/monasca/v2/reference/resource.py b/monasca/v2/reference/resource.py index c0bac8597..da0c3694e 100644 --- a/monasca/v2/reference/resource.py +++ b/monasca/v2/reference/resource.py @@ -34,6 +34,8 @@ def resource_try_catch_block(fun): raise falcon.HTTPNotFound except falcon.HTTPBadRequest: raise + except exceptions.AlreadyExistsException as ex: + raise falcon.HTTPConflict(ex.__class__.__name__, ex.message) except exceptions.RepositoryException as ex: LOG.exception(ex) msg = " ".join(map(str, ex.message.args)) diff --git a/ref-impl-requirements.txt b/ref-impl-requirements.txt index d1382c572..e7eaa85d2 100755 --- a/ref-impl-requirements.txt +++ b/ref-impl-requirements.txt @@ -8,6 +8,5 @@ influxdb>=0.1.12 MySQL-python -peewee>=2.3.3 Pyparsing>=2.0.3 voluptuous>=0.8.5 \ No newline at end of file