Support Client Notification Endpoint Test
This functionality will enable tacker to test the notification during register Subscription. if VNFM cannot receive success response (204 no content), VNFM will be failed Subscription Request - As sending management of this API, we apply legacy CONF. (retry_num,retry_wait, there are defined in vnf_lcm group.) - As sending control of this API, we add new CONF(test_callback_uri) - We modify(add) Notification(GET) process to current send_notification. Implements: blueprint support-fundamental-lcm Spec: https://specs.openstack.org/openstack/tacker-specs/specs/wallaby/support-fundamental-vnf-lcm-based-on-ETSI-NFV.html Change-Id: I2a1db1b34b687748ad939b0c867b2d78f45622da
This commit is contained in:
parent
6b4cf268a9
commit
943e0b0815
@ -940,6 +940,15 @@ class VnfLcmController(wsgi.Controller):
|
||||
filter_uni = subscription_request_data.get('filter')
|
||||
filter = ast.literal_eval(str(filter_uni).replace("'", "'"))
|
||||
|
||||
if CONF.vnf_lcm.test_callback_uri:
|
||||
resp = self._test_notification(request.context,
|
||||
vnf_lcm_subscription)
|
||||
if resp == -1:
|
||||
LOG.exception(traceback.format_exc())
|
||||
return self._make_problem_detail(
|
||||
'Failed to Test Notification', 400,
|
||||
title='Bad Request')
|
||||
|
||||
try:
|
||||
vnf_lcm_subscription = vnf_lcm_subscription.create(filter)
|
||||
LOG.debug("vnf_lcm_subscription %s" % vnf_lcm_subscription)
|
||||
@ -1526,6 +1535,11 @@ class VnfLcmController(wsgi.Controller):
|
||||
res.status_int = status
|
||||
return res
|
||||
|
||||
def _test_notification(self, context, vnf_lcm_subscription):
|
||||
resp = self.rpc_api.test_notification(context,
|
||||
vnf_lcm_subscription, cast=False)
|
||||
return resp
|
||||
|
||||
|
||||
def create_resource():
|
||||
return wsgi.Resource(VnfLcmController())
|
||||
|
@ -1467,11 +1467,6 @@ class Conductor(manager.Manager):
|
||||
"Failed to send notification {}. Details: {}".format(
|
||||
vnf_lcm_op_occs_id, str(ex)))
|
||||
|
||||
def _retry_check(self, retry_count):
|
||||
time.sleep(CONF.vnf_lcm.retry_wait)
|
||||
if retry_count == CONF.vnf_lcm.retry_num:
|
||||
LOG.warn("Number of retries exceeded retry count")
|
||||
|
||||
def send_notification(self, context, notification):
|
||||
"""Function to send notification to client
|
||||
|
||||
@ -1574,6 +1569,65 @@ class Conductor(manager.Manager):
|
||||
return -2
|
||||
return 0
|
||||
|
||||
def _retry_check(self, retry_count):
|
||||
time.sleep(CONF.vnf_lcm.retry_wait)
|
||||
if retry_count == CONF.vnf_lcm.retry_num:
|
||||
LOG.warn(
|
||||
"Number of retries exceeded retry count [%s]" %
|
||||
CONF.vnf_lcm.retry_num)
|
||||
|
||||
def test_notification(self, context, vnf_lcm_subscription=None):
|
||||
"""Function to send test notification to client
|
||||
|
||||
This function is used to send test notification
|
||||
to client during Register Subscription.
|
||||
|
||||
:returns: 0 if status code of the response is 204
|
||||
or if CONF.vnf_lcm.test_callback_uri is False,
|
||||
-1 if status code of the response is not 204
|
||||
"""
|
||||
|
||||
if not CONF.vnf_lcm.test_callback_uri:
|
||||
LOG.warning("Callback URI is %s", CONF.vnf_lcm.test_callback_uri)
|
||||
return 0
|
||||
|
||||
# Notification shipping
|
||||
for num in range(CONF.vnf_lcm.retry_num):
|
||||
try:
|
||||
auth_client = auth.auth_manager.get_auth_client(
|
||||
vnf_lcm_subscription.id)
|
||||
|
||||
notification = {}
|
||||
response = auth_client.get(
|
||||
vnf_lcm_subscription.callback_uri,
|
||||
data=json.dumps(notification),
|
||||
timeout=CONF.vnf_lcm.retry_timeout)
|
||||
|
||||
if response.status_code == 204:
|
||||
return 0
|
||||
else:
|
||||
LOG.warning(
|
||||
"Notification failed status[%s] \
|
||||
callback_uri[%s]" %
|
||||
(response.status_code,
|
||||
vnf_lcm_subscription.callback_uri))
|
||||
LOG.debug(
|
||||
"retry_wait %s" %
|
||||
CONF.vnf_lcm.retry_wait)
|
||||
self._retry_check(num)
|
||||
|
||||
continue
|
||||
except requests.Timeout as e:
|
||||
LOG.warning("Notification request timed out."
|
||||
" callback_uri[%(uri)s]"
|
||||
" reason[%(reason)s]", {
|
||||
"uri": vnf_lcm_subscription.callback_uri,
|
||||
"reason": str(e)})
|
||||
self._retry_check(num)
|
||||
|
||||
# return -1 since the response is not 204
|
||||
return -1
|
||||
|
||||
@coordination.synchronized('{vnf_instance[id]}')
|
||||
def instantiate(
|
||||
self,
|
||||
|
@ -113,6 +113,17 @@ class VNFLcmRPCAPI(object):
|
||||
return rpc_method(context, 'send_notification',
|
||||
notification=notification)
|
||||
|
||||
def test_notification(self, context,
|
||||
vnf_lcm_subscription=None, cast=False):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
||||
client = rpc.get_client(self.target, version_cap=None,
|
||||
serializer=serializer)
|
||||
cctxt = client.prepare()
|
||||
rpc_method = cctxt.cast if cast else cctxt.call
|
||||
return rpc_method(context, 'test_notification',
|
||||
vnf_lcm_subscription=vnf_lcm_subscription)
|
||||
|
||||
def rollback(self, context, vnf_info, vnf_instance,
|
||||
operation_params, cast=True):
|
||||
serializer = objects_base.TackerObjectSerializer()
|
||||
|
@ -35,7 +35,11 @@ OPTS = [
|
||||
cfg.IntOpt(
|
||||
'retry_timeout',
|
||||
default=10,
|
||||
help="Retry Timeout(sec)")]
|
||||
help="Retry Timeout(sec)"),
|
||||
cfg.BoolOpt(
|
||||
'test_callback_uri',
|
||||
default=True,
|
||||
help="Test callbackUri")]
|
||||
|
||||
vnf_lcm_group = cfg.OptGroup('vnf_lcm',
|
||||
title='vnf_lcm options',
|
||||
|
@ -237,6 +237,11 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
callback_url,
|
||||
status_code=204
|
||||
)
|
||||
FAKE_SERVER_MANAGER.set_callback(
|
||||
'GET',
|
||||
callback_url,
|
||||
status_code=204
|
||||
)
|
||||
|
||||
self.tacker_client = base.BaseTackerTest.tacker_http_client()
|
||||
|
||||
@ -1089,6 +1094,14 @@ class BaseVnfLcmTest(base.BaseTackerTest):
|
||||
'VnfLcmOperationOccurrenceNotification',
|
||||
'COMPLETED')
|
||||
|
||||
def assert_notification_get(self, callback_url):
|
||||
notify_mock_responses = FAKE_SERVER_MANAGER.get_history(
|
||||
callback_url)
|
||||
FAKE_SERVER_MANAGER.clear_history(
|
||||
callback_url)
|
||||
self.assertEqual(1, len(notify_mock_responses))
|
||||
self.assertEqual(204, notify_mock_responses[0].status_code)
|
||||
|
||||
def assert_notification_mock_response(
|
||||
self,
|
||||
notify_mock_response,
|
||||
|
@ -111,14 +111,16 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
- Delete subscription
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
callback_url))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
self.assert_notification_get(callback_url)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(
|
||||
self._delete_subscription,
|
||||
@ -237,14 +239,16 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
callback_url))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
self.assert_notification_get(callback_url)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
@ -388,14 +392,16 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
callback_url))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
self.assert_notification_get(callback_url)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
@ -1003,14 +1009,16 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
callback_url))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
self.assert_notification_get(callback_url)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
@ -1098,14 +1106,16 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
- Delete subscription.
|
||||
"""
|
||||
# Create subscription and register it.
|
||||
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
callback_url))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
self.assert_notification_get(callback_url)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
@ -1205,6 +1215,7 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create subscription.
|
||||
- Test notification.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
@ -1226,6 +1237,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
self.assert_notification_get(
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName))
|
||||
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = 'functional3'
|
||||
csar_package_path = os.path.abspath(
|
||||
@ -1303,6 +1318,7 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
|
||||
In this test case, we do following steps.
|
||||
- Create subscription.
|
||||
- Test notification.
|
||||
- Create VNF package.
|
||||
- Upload VNF package.
|
||||
- Create VNF instance.
|
||||
@ -1326,6 +1342,10 @@ class VnfLcmWithUserDataTest(vnflcm_base.BaseVnfLcmTest):
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
self.assert_notification_get(
|
||||
os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName))
|
||||
|
||||
# Pre Setting: Create vnf package.
|
||||
sample_name = 'functional4'
|
||||
csar_package_path = os.path.abspath(
|
||||
|
@ -108,15 +108,16 @@ class VnfLcmWithNfvoSeparator(vnflcm_base.BaseVnfLcmTest):
|
||||
glance_image = self._list_glance_image()[0]
|
||||
|
||||
# Create subscription and register it.
|
||||
callback_url = os.path.join(vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)
|
||||
request_body = fake_vnflcm.Subscription.make_create_request_body(
|
||||
'http://localhost:{}{}'.format(
|
||||
vnflcm_base.FAKE_SERVER_MANAGER.SERVER_PORT,
|
||||
os.path.join(
|
||||
vnflcm_base.MOCK_NOTIFY_CALLBACK_URL,
|
||||
self._testMethodName)))
|
||||
callback_url))
|
||||
resp, response_body = self._register_subscription(request_body)
|
||||
self.assertEqual(201, resp.status_code)
|
||||
self.assert_http_header_location_for_subscription(resp.headers)
|
||||
self.assert_notification_get(callback_url)
|
||||
subscription_id = response_body.get('id')
|
||||
self.addCleanup(self._delete_subscription, subscription_id)
|
||||
|
||||
|
@ -2734,7 +2734,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
def test_send_notification_rety_notification(self,
|
||||
def test_send_notification_retry_notification(self,
|
||||
mock_subscriptions_get):
|
||||
self.requests_mock.register_uri('POST',
|
||||
"https://localhost/callback",
|
||||
@ -2760,7 +2760,7 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
||||
|
||||
@mock.patch.object(objects.LccnSubscriptionRequest,
|
||||
'vnf_lcm_subscriptions_get')
|
||||
def test_sendNotification_sendError(self,
|
||||
def test_send_notification_send_error(self,
|
||||
mock_subscriptions_get):
|
||||
self.requests_mock.register_uri(
|
||||
'POST',
|
||||
@ -2818,10 +2818,118 @@ class TestConductor(SqlTestCase, unit_base.FixturedTestCase):
|
||||
# return value when timeout for POST method is 0
|
||||
self.assertEqual(result, 0)
|
||||
|
||||
def test_get_notification(self):
|
||||
cfg.CONF.set_override('test_callback_uri', True,
|
||||
group='vnf_lcm')
|
||||
self.requests_mock.register_uri('GET',
|
||||
"https://localhost/callback",
|
||||
headers={
|
||||
'Content-Type': 'application/json'},
|
||||
status_code=204)
|
||||
|
||||
callback_uri = 'https://localhost/callback'
|
||||
|
||||
vnf_lcm_subscription = objects.\
|
||||
LccnSubscriptionRequest(context=self.context)
|
||||
vnf_lcm_subscription.id = uuidsentinel.lcm_subscription_id
|
||||
vnf_lcm_subscription.callback_uri = callback_uri
|
||||
|
||||
result = self.conductor.test_notification(self.context,
|
||||
vnf_lcm_subscription)
|
||||
|
||||
# return value when successful for GET method is 0
|
||||
self.assertEqual(result, 0)
|
||||
|
||||
history = self.requests_mock.request_history
|
||||
req_count = nfvo_client._count_mock_history(
|
||||
history, "https://localhost")
|
||||
self.assertEqual(1, req_count)
|
||||
cfg.CONF.set_override('test_callback_uri', False,
|
||||
group='vnf_lcm')
|
||||
|
||||
def test_get_notification_callback_uri_false(self):
|
||||
cfg.CONF.set_override('test_callback_uri', False,
|
||||
group='vnf_lcm')
|
||||
self.requests_mock.register_uri('GET',
|
||||
"https://localhost/callback",
|
||||
headers={
|
||||
'Content-Type': 'application/json'},
|
||||
status_code=204)
|
||||
|
||||
callback_uri = 'https://localhost/callback'
|
||||
|
||||
vnf_lcm_subscription = objects.\
|
||||
LccnSubscriptionRequest(context=self.context)
|
||||
vnf_lcm_subscription.id = uuidsentinel.lcm_subscription_id
|
||||
vnf_lcm_subscription.callback_uri = callback_uri
|
||||
|
||||
result = self.conductor.test_notification(self.context,
|
||||
vnf_lcm_subscription)
|
||||
|
||||
# return value when successful for GET method is 0
|
||||
self.assertEqual(result, 0)
|
||||
|
||||
history = self.requests_mock.request_history
|
||||
req_count = nfvo_client._count_mock_history(
|
||||
history, "https://localhost")
|
||||
self.assertEqual(0, req_count)
|
||||
|
||||
def test_get_notification_retry(self):
|
||||
cfg.CONF.set_override('test_callback_uri', True,
|
||||
group='vnf_lcm')
|
||||
self.requests_mock.register_uri('GET',
|
||||
"https://localhost/callback",
|
||||
headers={
|
||||
'Content-Type': 'application/json'},
|
||||
status_code=400)
|
||||
|
||||
callback_uri = 'https://localhost/callback'
|
||||
|
||||
vnf_lcm_subscription = objects.\
|
||||
LccnSubscriptionRequest(context=self.context)
|
||||
vnf_lcm_subscription.id = uuidsentinel.lcm_subscription_id
|
||||
vnf_lcm_subscription.callback_uri = callback_uri
|
||||
|
||||
result = self.conductor.test_notification(self.context,
|
||||
vnf_lcm_subscription)
|
||||
|
||||
# return value when error occurs for GET method is -1
|
||||
self.assertEqual(result, -1)
|
||||
|
||||
history = self.requests_mock.request_history
|
||||
req_count = nfvo_client._count_mock_history(
|
||||
history, "https://localhost")
|
||||
self.assertEqual(3, req_count)
|
||||
cfg.CONF.set_override('test_callback_uri', False,
|
||||
group='vnf_lcm')
|
||||
|
||||
def test_get_notification_timeout(self):
|
||||
cfg.CONF.set_override('test_callback_uri', True,
|
||||
group='vnf_lcm')
|
||||
self.requests_mock.register_uri(
|
||||
'GET',
|
||||
"https://localhost/callback",
|
||||
exc=requests.Timeout)
|
||||
|
||||
callback_uri = 'https://localhost/callback'
|
||||
|
||||
vnf_lcm_subscription = objects.\
|
||||
LccnSubscriptionRequest(context=self.context)
|
||||
vnf_lcm_subscription.id = uuidsentinel.lcm_subscription_id
|
||||
vnf_lcm_subscription.callback_uri = callback_uri
|
||||
|
||||
result = self.conductor.test_notification(self.context,
|
||||
vnf_lcm_subscription)
|
||||
|
||||
# return value when error for GET method is -1
|
||||
self.assertEqual(result, -1)
|
||||
|
||||
history = self.requests_mock.request_history
|
||||
req_count = nfvo_client._count_mock_history(
|
||||
history, "https://localhost")
|
||||
self.assertEqual(3, req_count)
|
||||
cfg.CONF.set_override('test_callback_uri', False,
|
||||
group='vnf_lcm')
|
||||
|
||||
@mock.patch.object(conductor_server, 'revert_update_lcm')
|
||||
@mock.patch.object(t_context.get_admin_context().session, "add")
|
||||
|
Loading…
Reference in New Issue
Block a user