Cole Walker 6a2e65d412 [PTP] Fix logic for handling incorrect v2 subscription POST
Fixed an issue where attempting to GET a subscription by ID was
failing. DELETE by subscription ID was also failing.
The logic to return 404 on an incorrect v2 subscription POST was
breaking the ability to get subscriptions by ID. Added a dedicated
method to handle the incorrect POST and returned the subscription GET
logic to the original form.

Test plan:
PASS: Build and deploy notification-client base
PASS: Test v1 and v2 pull status, subscribe, get subscription, delete
PASS: Invalid POST to v2 subscription endpoint returns 404

Closes-bug: 1998394

Signed-off-by: Cole Walker <cole.walker@windriver.com>
Change-Id: I3c67af481d86966fcb78270c34ad9f6e6468c63c
2022-11-30 16:18:39 -05:00

179 lines
6.4 KiB
Python

#
# Copyright (c) 2021-2022 Wind River Systems, Inc.
#
# SPDX-License-Identifier: Apache-2.0
#
from pecan import conf
from pecan import expose, rest, response, abort
from webob.exc import HTTPException, HTTPServerError
import logging
from wsmeext.pecan import wsexpose
from notificationclientsdk.model.dto.subscription import SubscriptionInfoV2
from notificationclientsdk.repository.subscription_repo import SubscriptionRepo
from notificationclientsdk.services.ptp import PtpService
from notificationclientsdk.exception import client_exception
from notificationclientsdk.common.helpers import log_helper
from sidecar.repository.notification_control import notification_control
from sidecar.repository.dbcontext_default import defaults
LOG = logging.getLogger(__name__)
log_helper.config_logger(LOG)
class SubscriptionsControllerV2(rest.RestController):
@wsexpose(SubscriptionInfoV2, body=SubscriptionInfoV2, status_code=201)
def post(self, subscription):
# decode the request body
try:
if subscription.ResourceAddress:
LOG.info('subscribe: ResourceAddress {0} with '
'callback uri {1}'.format(
subscription.ResourceAddress,
subscription.EndpointUri))
if not self._validateV2(subscription):
LOG.warning('Invalid Request data:{0}'.format(
subscription.to_dict()))
abort(400)
subscription.UriLocation = \
"{0}://{1}:{2}/ocloudNotifications/v2/subscriptions".format(
conf.server.get('protocol', 'http'),
conf.server.get('host', '127.0.0.1'),
conf.server.get('port', '8080')
)
if subscription.ResourceAddress:
ptpservice = PtpService(notification_control)
entry = ptpservice.add_subscription(subscription)
subscription.SubscriptionId = entry.SubscriptionId
subscription.UriLocation = entry.UriLocation
LOG.info('created subscription: {0}'.format(
subscription.to_dict()))
del ptpservice
return subscription
except client_exception.ServiceError as err:
abort(int(str(err)))
except client_exception.InvalidSubscription:
abort(400)
except client_exception.InvalidEndpoint as ex:
abort(400, str(ex))
except client_exception.InvalidResource as ex:
abort(400, str(ex))
except client_exception.NodeNotAvailable:
abort(404)
except client_exception.ResourceNotAvailable:
abort(404)
except HTTPException as ex:
LOG.warning("Client side error:{0},{1}".format(type(ex), str(ex)))
abort(400)
except HTTPServerError as ex:
LOG.error("Server side error:{0},{1}".format(type(ex), str(ex)))
abort(500)
except Exception as ex:
LOG.error("Exception:{0}@{1}".format(type(ex), str(ex)))
abort(500)
@expose('json')
def get(self):
try:
repo = SubscriptionRepo(defaults['dbcontext'].get_session(),
autocommit=False)
entries = repo.get(Status=1)
response.status = 200
subs = []
for x in entries:
if x.Status == 1:
if getattr(x, 'ResourceAddress', None) is not None:
subs.append(SubscriptionInfoV2(x).to_dict())
return subs
except HTTPException as ex:
LOG.warning("Client side error:{0},{1}".format(type(ex), str(ex)))
raise ex
except HTTPServerError as ex:
LOG.error("Server side error:{0},{1}".format(type(ex), str(ex)))
raise ex
except Exception as ex:
LOG.error("Exception:{0}@{1}".format(type(ex), str(ex)))
abort(500)
@expose()
def _lookup(self, subscription_id, *remainder):
return SubscriptionController(subscription_id), remainder
def _validateV2(self, subscription_request):
try:
assert subscription_request.ResourceAddress
assert subscription_request.EndpointUri
return True
except Exception:
return False
class SubscriptionController(rest.RestController):
def __init__(self, subscription_id):
self.subscription_id = subscription_id
@expose('json')
def post(self):
abort(404)
@expose('json')
def get(self):
try:
repo = SubscriptionRepo(defaults['dbcontext'].get_session(),
autocommit=False)
entry = repo.get_one(SubscriptionId=self.subscription_id, Status=1)
if not entry:
abort(404)
else:
response.status = 200
if getattr(entry, 'ResourceAddress', None):
return SubscriptionInfoV2(entry).to_dict()
except HTTPException as ex:
LOG.warning("Client side error:{0},{1}".format(type(ex), str(ex)))
raise ex
except HTTPServerError as ex:
LOG.error("Server side error:{0},{1}".format(type(ex), str(ex)))
raise ex
except Exception as ex:
LOG.error("Exception:{0}@{1}".format(type(ex), str(ex)))
abort(500)
@wsexpose(status_code=204)
def delete(self):
try:
repo = SubscriptionRepo(defaults['dbcontext'].get_session(),
autocommit=False)
entry = repo.get_one(SubscriptionId=self.subscription_id)
if entry:
if entry.SubscriptionId:
ptpservice = PtpService(notification_control)
ptpservice.remove_subscription(entry.SubscriptionId)
del ptpservice
return
else:
repo.delete_one(SubscriptionId=self.subscription_id)
return
abort(404)
except HTTPException as ex:
LOG.warning("Client side error:{0},{1}".format(type(ex), str(ex)))
raise ex
except HTTPServerError as ex:
LOG.error("Server side error:{0},{1}".format(type(ex), str(ex)))
raise ex
except Exception as ex:
LOG.error("Exception:{0}@{1}".format(type(ex), str(ex)))
abort(500)