aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorhongyuzhao <zhao.hongyu@zte.com.cn>2019-11-13 15:59:21 +0800
committerhongyuzhao <zhao.hongyu@zte.com.cn>2019-11-14 15:56:48 +0800
commit4004afdf54c246b4afd481003aca16d2dab816fb (patch)
treeb6f80bf054813feb9c48c7acf1ff2a073832539a
parent0b6a49e188b44602ca83a5802b6820b32d3e2a35 (diff)
Notify about VNF package on-boarding or change
Change-Id: Iedba1b62577f99f106c4309620b8129b775df2e4 Signed-off-by: hongyuzhao <zhao.hongyu@zte.com.cn> Issue-ID: MODELING-269
-rw-r--r--catalog/packages/biz/notificationsutil.py162
-rw-r--r--catalog/packages/biz/vnf_package.py54
-rw-r--r--catalog/packages/const.py16
-rw-r--r--catalog/packages/tests/test_nsdm_subscription.py98
-rw-r--r--catalog/packages/tests/test_vnf_pkg_subscription.py63
-rw-r--r--catalog/pub/utils/tests.py1
6 files changed, 377 insertions, 17 deletions
diff --git a/catalog/packages/biz/notificationsutil.py b/catalog/packages/biz/notificationsutil.py
new file mode 100644
index 0000000..04bad47
--- /dev/null
+++ b/catalog/packages/biz/notificationsutil.py
@@ -0,0 +1,162 @@
+# Copyright 2019 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import logging
+import uuid
+import requests
+from rest_framework import status
+from catalog.packages import const
+from catalog.pub.database.models import VnfPkgSubscriptionModel, NsdmSubscriptionModel
+from catalog.pub.database.models import VnfPackageModel
+import catalog.pub.utils.timeutil
+from catalog.pub.utils.values import remove_none_key
+from catalog.pub.config import config as pub_config
+import traceback
+
+logger = logging.getLogger(__name__)
+
+
+class NotificationsUtil(object):
+ def __init__(self):
+ pass
+
+ def send_notification(self, notification, filters, isvnfpkg):
+ logger.info("Send Notifications to the callbackUri")
+ subscriptions_filter = {v + "__contains": notification[k] for k, v in filters.items()}
+ logger.debug('send_notification subscriptions_filter = %s' % subscriptions_filter)
+ subscriptions_filter = remove_none_key(subscriptions_filter)
+ if isvnfpkg:
+ subscriptions = VnfPkgSubscriptionModel.objects.filter(**subscriptions_filter)
+ subscription_root_uri = const.VNFPKG_SUBSCRIPTION_ROOT_URI
+ else:
+ subscriptions = NsdmSubscriptionModel.objects.filter(**subscriptions_filter)
+ subscription_root_uri = const.NSDM_SUBSCRIPTION_ROOT_URI
+ if not subscriptions.exists():
+ logger.info("No subscriptions created for the filters %s" % notification)
+ return
+ logger.info("Start sending notifications")
+ for sub in subscriptions:
+ # set subscription id
+ if isvnfpkg:
+ notification["subscriptionId"] = sub.subscription_id
+ else:
+ notification["subscriptionId"] = sub.subscriptionid
+ notification['_links']['subscription'] = {
+ 'href': 'http://%s:%s/%s%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ subscription_root_uri,
+ notification["subscriptionId"])
+ }
+ callbackuri = sub.callback_uri
+ """
+ auth_info = json.loads(sub.auth_info)
+ if auth_info["authType"] == const.OAUTH2_CLIENT_CREDENTIALS:
+ pass
+ """
+ self.post_notification(callbackuri, notification)
+
+ def post_notification(self, callbackuri, notification):
+ """
+ params = auth_info.get("paramsBasic", {})
+ username, password = params.get("userName"), params.get("password")
+ logger.info("Sending notification to %s, %s", callbackuri, params)
+ resp = None
+ if username:
+ resp = requests.post(callbackuri,
+ data=notification,
+ auth=HTTPBasicAuth(username, password))
+ else:
+ """
+
+ try:
+ resp = requests.post(callbackuri, data=notification, headers={'Connection': 'close'})
+ if resp.status_code != status.HTTP_204_NO_CONTENT:
+ logger.error("Sendingnotification to %s failed: %s" % (callbackuri, resp.text))
+ else:
+ logger.info("Sending notification to %s successfully.", callbackuri)
+ except:
+ logger.error("Post notification failed.")
+ logger.error(traceback.format_exc())
+
+
+def prepare_vnfpkg_notification(vnf_pkg_id, notification_type, pkg_change_type, operational_state):
+ logger.info('Start to prepare notification')
+ vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
+ vnfd_id = None
+ if vnf_pkg:
+ vnfd_id = vnf_pkg[0].vnfdId
+ notification_content = {
+ 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
+ 'notificationType': notification_type,
+ # set 'subscriptionId' after filtering for subscribers
+ 'timeStamp': catalog.pub.utils.timeutil.now_time(),
+ 'vnfPkgId': vnf_pkg_id,
+ 'vnfdId': vnfd_id,
+ 'changeType': pkg_change_type,
+ 'operationalState': operational_state,
+ '_links': {
+ 'vnfPackage': {
+ 'href': 'http://%s:%s/%s/vnf_packages/%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.PKG_URL_PREFIX,
+ vnf_pkg_id)
+ }
+ }
+ }
+ return notification_content
+
+
+def prepare_nsd_notification(nsd_info_id, nsd_id, notification_type, failure_details=None, operational_state=None):
+ logger.info('Start to prepare notification')
+ notification_content = {
+ 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
+ 'notificationType': notification_type,
+ # set 'subscriptionId' after filtering for subscribers
+ 'timeStamp': catalog.pub.utils.timeutil.now_time(),
+ 'nsdInfoId': nsd_info_id,
+ 'nsdId': nsd_id,
+ 'onboardingFailureDetails': failure_details,
+ 'nsdOperationalState': operational_state,
+ '_links': {
+ 'nsdInfo': {
+ 'href': 'http://%s:%s/%s/ns_descriptors/%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.NSD_URL_PREFIX,
+ nsd_info_id)
+ }
+ }
+ }
+ return notification_content
+
+
+def prepare_pnfd_notification(pnfd_info_id, pnfd_id, notification_type, failure_details=None):
+ logger.info('Start to prepare notification')
+ notification_content = {
+ 'id': str(uuid.uuid4()), # shall be the same if sent multiple times due to multiple subscriptions.
+ 'notificationType': notification_type,
+ # set 'subscriptionId' after filtering for subscribers
+ 'timeStamp': catalog.pub.utils.timeutil.now_time(),
+ 'pnfdInfoIds': pnfd_info_id,
+ 'pnfdId': pnfd_id,
+ 'onboardingFailureDetails': failure_details,
+ '_links': {
+ 'pnfdInfo': {
+ 'href': 'http://%s:%s/%s/pnf_descriptors/%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.NSD_URL_PREFIX,
+ pnfd_info_id)
+ }
+ }
+ }
+ return notification_content
diff --git a/catalog/packages/biz/vnf_package.py b/catalog/packages/biz/vnf_package.py
index 585a599..21d5819 100644
--- a/catalog/packages/biz/vnf_package.py
+++ b/catalog/packages/biz/vnf_package.py
@@ -27,7 +27,8 @@ from catalog.pub.database.models import VnfPackageModel, NSPackageModel
from catalog.pub.exceptions import CatalogException, ResourceNotFoundException
from catalog.pub.utils.values import ignore_case_get
from catalog.pub.utils import fileutil, toscaparser
-from catalog.packages.const import PKG_STATUS
+from catalog.packages import const
+from catalog.packages.biz.notificationsutil import prepare_vnfpkg_notification, NotificationsUtil
logger = logging.getLogger(__name__)
@@ -43,16 +44,16 @@ class VnfPackage(object):
vnf_pkg_id = str(uuid.uuid4())
VnfPackageModel.objects.create(
vnfPackageId=vnf_pkg_id,
- onboardingState=PKG_STATUS.CREATED,
- operationalState=PKG_STATUS.DISABLED,
- usageState=PKG_STATUS.NOT_IN_USE,
+ onboardingState=const.PKG_STATUS.CREATED,
+ operationalState=const.PKG_STATUS.DISABLED,
+ usageState=const.PKG_STATUS.NOT_IN_USE,
userDefinedData=json.dumps(user_defined_data)
)
data = {
"id": vnf_pkg_id,
- "onboardingState": PKG_STATUS.CREATED,
- "operationalState": PKG_STATUS.DISABLED,
- "usageState": PKG_STATUS.NOT_IN_USE,
+ "onboardingState": const.PKG_STATUS.CREATED,
+ "operationalState": const.PKG_STATUS.DISABLED,
+ "usageState": const.PKG_STATUS.NOT_IN_USE,
"userDefinedData": user_defined_data,
"_links": None
}
@@ -96,6 +97,9 @@ class VnfPackage(object):
if del_vnfd_id == vnf["properties"]["descriptor_id"]:
raise CatalogException('VNFD(%s) is referenced.' % del_vnfd_id)
vnf_pkg.delete()
+ send_notification(vnf_pkg_id, const.PKG_NOTIFICATION_TYPE.CHANGE,
+ const.PKG_CHANGE_TYPE.PKG_DELETE)
+
vnf_pkg_path = os.path.join(CATALOG_ROOT_PATH, vnf_pkg_id)
fileutil.delete_dirs(vnf_pkg_path)
logger.info('VNF package(%s) has been deleted.' % vnf_pkg_id)
@@ -106,7 +110,9 @@ class VnfPackage(object):
# if vnf_pkg[0].onboardingState != PKG_STATUS.CREATED:
# logger.error("VNF package(%s) is not CREATED" % vnf_pkg_id)
# raise CatalogException("VNF package(%s) is not CREATED" % vnf_pkg_id)
- vnf_pkg.update(onboardingState=PKG_STATUS.UPLOADING)
+ vnf_pkg.update(onboardingState=const.PKG_STATUS.UPLOADING)
+ send_notification(vnf_pkg_id, const.PKG_NOTIFICATION_TYPE.ONBOARDING,
+ const.PKG_CHANGE_TYPE.OP_STATE_CHANGE)
local_file_name = save(remote_file, vnf_pkg_id)
logger.info('VNF package(%s) has been uploaded.' % vnf_pkg_id)
@@ -118,7 +124,7 @@ class VnfPackage(object):
if not nf_pkg.exists():
logger.error('VNF package(%s) does not exist.' % vnf_pkg_id)
raise ResourceNotFoundException('VNF package(%s) does not exist.' % vnf_pkg_id)
- if nf_pkg[0].onboardingState != PKG_STATUS.ONBOARDED:
+ if nf_pkg[0].onboardingState != const.PKG_STATUS.ONBOARDED:
raise CatalogException("VNF package (%s) is not on-boarded" % vnf_pkg_id)
local_file_path = nf_pkg[0].localFilePath
@@ -148,10 +154,12 @@ class VnfPkgUploadThread(threading.Thread):
def upload_vnf_pkg_from_uri(self):
logger.info("Start to upload VNF packge(%s) from URI..." % self.vnf_pkg_id)
vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=self.vnf_pkg_id)
- if vnf_pkg[0].onboardingState != PKG_STATUS.CREATED:
+ if vnf_pkg[0].onboardingState != const.PKG_STATUS.CREATED:
logger.error("VNF package(%s) is not CREATED" % self.vnf_pkg_id)
raise CatalogException("VNF package (%s) is not created" % self.vnf_pkg_id)
- vnf_pkg.update(onboardingState=PKG_STATUS.UPLOADING)
+ vnf_pkg.update(onboardingState=const.PKG_STATUS.UPLOADING)
+ send_notification(self.vnf_pkg_id, const.PKG_NOTIFICATION_TYPE.ONBOARDING,
+ const.PKG_CHANGE_TYPE.OP_STATE_CHANGE)
uri = ignore_case_get(self.data, "addressInformation")
response = urllib.request.urlopen(uri)
@@ -189,7 +197,7 @@ def fill_response_data(nf_pkg):
def parse_vnfd_and_save(vnf_pkg_id, vnf_pkg_path):
logger.info('Start to process VNF package(%s)...' % vnf_pkg_id)
vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
- vnf_pkg.update(onboardingState=PKG_STATUS.PROCESSING)
+ vnf_pkg.update(onboardingState=const.PKG_STATUS.PROCESSING)
vnfd_json = toscaparser.parse_vnfd(vnf_pkg_path)
vnfd = json.JSONDecoder().decode(vnfd_json)
@@ -211,9 +219,9 @@ def parse_vnfd_and_save(vnf_pkg_id, vnf_pkg_path):
vnfdVersion=vnfd_ver,
vnfSoftwareVersion=vnf_software_version,
vnfdModel=vnfd_json,
- onboardingState=PKG_STATUS.ONBOARDED,
- operationalState=PKG_STATUS.ENABLED,
- usageState=PKG_STATUS.NOT_IN_USE,
+ onboardingState=const.PKG_STATUS.ONBOARDED,
+ operationalState=const.PKG_STATUS.ENABLED,
+ usageState=const.PKG_STATUS.NOT_IN_USE,
localFilePath=vnf_pkg_path,
vnfPackageUri=os.path.split(vnf_pkg_path)[-1]
)
@@ -224,4 +232,18 @@ def parse_vnfd_and_save(vnf_pkg_id, vnf_pkg_path):
def handle_upload_failed(vnf_pkg_id):
vnf_pkg = VnfPackageModel.objects.filter(vnfPackageId=vnf_pkg_id)
- vnf_pkg.update(onboardingState=PKG_STATUS.CREATED)
+ vnf_pkg.update(onboardingState=const.PKG_STATUS.CREATED)
+
+
+def send_notification(pkg_id, type, pkg_change_type, operational_state=None):
+ data = prepare_vnfpkg_notification(vnf_pkg_id=pkg_id,
+ notification_type=type,
+ pkg_change_type=pkg_change_type,
+ operational_state=operational_state)
+ filters = {
+ 'vnfdId': 'vnfd_id',
+ 'vnfPkgId': 'vnf_pkg_id'
+ }
+ logger.debug('Notify request data = %s' % data)
+ logger.debug('Notify request filters = %s' % filters)
+ NotificationsUtil().send_notification(data, filters, True)
diff --git a/catalog/packages/const.py b/catalog/packages/const.py
index cd09b40..593f3a2 100644
--- a/catalog/packages/const.py
+++ b/catalog/packages/const.py
@@ -39,6 +39,22 @@ NOTIFICATION_TYPES = [
"VnfPackageOnboardingNotification",
"VnfPackageChangeNotification"
]
+PKG_CHANGE_TYPE = enum(OP_STATE_CHANGE="OP_STATE_CHANGE", PKG_DELETE="PKG_DELETE")
+
+PKG_NOTIFICATION_TYPE = enum(ONBOARDING="VnfPackageOnboardingNotification",
+ CHANGE="VnfPackageChangeNotification")
+
+NSD_NOTIFICATION_TYPE = enum(NSD_ONBOARDING="NsdOnBoardingNotification",
+ NSD_ONBOARDING_FAILURE="NsdOnboardingFailureNotification",
+ NSD_CHANGE="NsdChangeNotification",
+ NSD_DELETION="NsdDeletionNotification",
+ PNFD_ONBOARDING="PnfdOnBoardingNotification",
+ PNFD_ONBOARDING_FAILURE="PnfdOnBoardingFailureNotification",
+ PNFD_DELETION="PnfdDeletionNotification")
+
+PKG_URL_PREFIX = "api/vnfpkgm/v1"
+
+NSD_URL_PREFIX = "api/nsd/v1"
VNFPKG_SUBSCRIPTION_ROOT_URI = "api/vnfpkgm/v1/subscriptions/"
diff --git a/catalog/packages/tests/test_nsdm_subscription.py b/catalog/packages/tests/test_nsdm_subscription.py
index f73c416..efed00c 100644
--- a/catalog/packages/tests/test_nsdm_subscription.py
+++ b/catalog/packages/tests/test_nsdm_subscription.py
@@ -21,6 +21,10 @@ from rest_framework import status
from catalog.packages.biz.nsdm_subscription import NsdmSubscription
from catalog.pub.database.models import NsdmSubscriptionModel
+from catalog.packages.biz.notificationsutil import NotificationsUtil, prepare_nsd_notification, prepare_pnfd_notification
+from catalog.packages import const
+from catalog.pub.config import config as pub_config
+import catalog.pub.utils.timeutil
class TestNsdmSubscription(TestCase):
@@ -519,3 +523,97 @@ class TestNsdmSubscription(TestCase):
format='json')
self.assertEqual(response.status_code,
status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class NotificationTest(TestCase):
+ def setUp(self):
+ NsdmSubscriptionModel(subscriptionid="1",
+ callback_uri="http://127.0.0.1/self",
+ notificationTypes=const.NOTIFICATION_TYPES,
+ nsdId="nsdid1",
+ nsdInfoId="nsdinfoid1",
+ pnfdInfoIds="pnfdInfoIds1",
+ pnfdId="pnfdId1"
+ ).save()
+
+ def tearDown(self):
+ NsdmSubscriptionModel.objects.all().delete()
+
+ @mock.patch("requests.post")
+ @mock.patch("uuid.uuid4")
+ @mock.patch.object(catalog.pub.utils.timeutil, "now_time")
+ def test_nsdpkg_notify(self, mock_nowtime, mock_uuid, mock_requests_post):
+ mock_nowtime.return_value = "nowtime()"
+ mock_uuid.return_value = "1111"
+ notification_content = prepare_nsd_notification("nsdinfoid1", "nsdid1",
+ const.NSD_NOTIFICATION_TYPE.NSD_ONBOARDING_FAILURE,
+ "NSD(nsdid1) already exists.", operational_state=None)
+ filters = {
+ 'nsdInfoId': 'nsdInfoId',
+ 'nsdId': 'nsdId',
+ }
+ NotificationsUtil().send_notification(notification_content, filters, False)
+ expect_callbackuri = "http://127.0.0.1/self"
+ expect_notification = {
+ 'id': "1111",
+ 'notificationType': const.NSD_NOTIFICATION_TYPE.NSD_ONBOARDING_FAILURE,
+ 'timeStamp': "nowtime()",
+ 'nsdInfoId': "nsdinfoid1",
+ 'nsdId': "nsdid1",
+ 'onboardingFailureDetails': "NSD(nsdid1) already exists.",
+ 'nsdOperationalState': None,
+ "subscriptionId": "1",
+ '_links': {
+ 'subscription': {
+ 'href': 'http://%s:%s/%s%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.NSDM_SUBSCRIPTION_ROOT_URI,
+ "1")},
+ 'nsdInfo': {
+ 'href': 'http://%s:%s/%s/ns_descriptors/%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.NSD_URL_PREFIX,
+ "nsdinfoid1")
+ }
+ }
+ }
+ mock_requests_post.assert_called_with(expect_callbackuri, data=expect_notification, headers={'Connection': 'close'})
+
+ @mock.patch("requests.post")
+ @mock.patch("uuid.uuid4")
+ @mock.patch.object(catalog.pub.utils.timeutil, "now_time")
+ def test_pnfpkg_notify(self, mock_nowtime, mock_uuid, mock_requests_post):
+ mock_nowtime.return_value = "nowtime()"
+ mock_uuid.return_value = "1111"
+ notification_content = prepare_pnfd_notification("pnfdInfoIds1", 'pnfdId1',
+ const.NSD_NOTIFICATION_TYPE.PNFD_ONBOARDING)
+ filters = {
+ 'pnfdId': 'pnfdId',
+ 'pnfdInfoIds': 'pnfdInfoIds',
+ }
+ NotificationsUtil().send_notification(notification_content, filters, False)
+ expect_callbackuri = "http://127.0.0.1/self"
+ expect_notification = {
+ 'id': "1111",
+ 'notificationType': const.NSD_NOTIFICATION_TYPE.PNFD_ONBOARDING,
+ 'timeStamp': "nowtime()",
+ 'pnfdInfoIds': "pnfdInfoIds1",
+ 'pnfdId': "pnfdId1",
+ 'onboardingFailureDetails': None,
+ "subscriptionId": "1",
+ '_links': {
+ 'subscription': {
+ 'href': 'http://%s:%s/%s%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.NSDM_SUBSCRIPTION_ROOT_URI,
+ "1")},
+ 'pnfdInfo': {
+ 'href': 'http://%s:%s/%s/pnf_descriptors/%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.NSD_URL_PREFIX,
+ "pnfdInfoIds1")
+ }
+ }
+ }
+ mock_requests_post.assert_called_with(expect_callbackuri, data=expect_notification,
+ headers={'Connection': 'close'})
diff --git a/catalog/packages/tests/test_vnf_pkg_subscription.py b/catalog/packages/tests/test_vnf_pkg_subscription.py
index 635b137..f2fe150 100644
--- a/catalog/packages/tests/test_vnf_pkg_subscription.py
+++ b/catalog/packages/tests/test_vnf_pkg_subscription.py
@@ -18,8 +18,12 @@ import mock
from rest_framework.test import APIClient
from django.test import TestCase
-from catalog.pub.database.models import VnfPkgSubscriptionModel
+from catalog.pub.database.models import VnfPkgSubscriptionModel, VnfPackageModel
from .const import vnf_subscription_data
+from catalog.packages.biz.notificationsutil import NotificationsUtil, prepare_vnfpkg_notification
+from catalog.packages import const
+from catalog.pub.config import config as pub_config
+import catalog.pub.utils.timeutil
class TestNfPackageSubscription(TestCase):
@@ -181,3 +185,60 @@ class TestNfPackageSubscription(TestCase):
dummy_uuid = str(uuid.uuid4())
response = self.client.delete("/api/vnfpkgm/v1/subscriptions/%s" % dummy_uuid)
self.assertEqual(404, response.status_code)
+
+
+class NotificationTest(TestCase):
+ def setUp(self):
+ VnfPackageModel(vnfPackageId="vnfpkgid1",
+ vnfdId="vnfdid1"
+ ).save()
+
+ VnfPkgSubscriptionModel(subscription_id="1",
+ callback_uri="http://127.0.0.1/self",
+ notification_types=const.NOTIFICATION_TYPES,
+ vnfd_id="vnfdid1",
+ vnf_pkg_id="vnfpkgid1"
+ ).save()
+
+ def tearDown(self):
+ VnfPackageModel.objects.all().delete()
+ VnfPkgSubscriptionModel.objects.all().delete()
+
+ @mock.patch("requests.post")
+ @mock.patch("uuid.uuid4")
+ @mock.patch.object(catalog.pub.utils.timeutil, "now_time")
+ def test_vnfpkg_notify(self, mock_nowtime, mock_uuid, mock_requests_post):
+ mock_nowtime.return_value = "nowtime()"
+ mock_uuid.return_value = "1111"
+ notification_content = prepare_vnfpkg_notification("vnfpkgid1", const.PKG_NOTIFICATION_TYPE.CHANGE,
+ const.PKG_CHANGE_TYPE.OP_STATE_CHANGE, operational_state=None)
+ filters = {
+ 'vnfdId': 'vnfd_id',
+ 'vnfPkgId': 'vnf_pkg_id'
+ }
+ NotificationsUtil().send_notification(notification_content, filters, True)
+ expect_callbackuri = "http://127.0.0.1/self"
+ expect_notification = {
+ 'id': "1111",
+ 'notificationType': const.PKG_NOTIFICATION_TYPE.CHANGE,
+ 'timeStamp': "nowtime()",
+ 'vnfPkgId': "vnfpkgid1",
+ 'vnfdId': "vnfdid1",
+ 'changeType': const.PKG_CHANGE_TYPE.OP_STATE_CHANGE,
+ 'operationalState': None,
+ "subscriptionId": "1",
+ '_links': {
+ 'subscription': {
+ 'href': 'http://%s:%s/%s%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.VNFPKG_SUBSCRIPTION_ROOT_URI,
+ "1")},
+ 'vnfPackage': {
+ 'href': 'http://%s:%s/%s/vnf_packages/%s' % (pub_config.MSB_SERVICE_IP,
+ pub_config.MSB_SERVICE_PORT,
+ const.PKG_URL_PREFIX,
+ "vnfpkgid1")
+ }
+ }
+ }
+ mock_requests_post.assert_called_with(expect_callbackuri, data=expect_notification, headers={'Connection': 'close'})
diff --git a/catalog/pub/utils/tests.py b/catalog/pub/utils/tests.py
index 0f02467..3698c59 100644
--- a/catalog/pub/utils/tests.py
+++ b/catalog/pub/utils/tests.py
@@ -15,6 +15,7 @@
import platform
import unittest
import mock
+
from . import fileutil
import urllib
from . import syscomm