From 5584b6495ca1c2422077feb44f156c485874feeb Mon Sep 17 00:00:00 2001 From: Dario Faccin Date: Wed, 24 May 2023 10:21:37 +0200 Subject: [PATCH] Update from master Squashed commit of the following: commit 0389d9e766bb7049d45dbcc9e322de22c7203fae Author: selvi.j Date: Wed Apr 26 12:13:10 2023 +0000 Coverity-CWE 330: Use of Insufficiently Random Values Added fix for CWE 330: Use of Insufficiently Random Value (Cryptographically weak PRNG) Change-Id: If17007c4e14fa91b3c378a504e7fbd03ea44a69b Signed-off-by: selvi.j commit 375aeb2647d733ac894b2408f66d36d55217c92d Author: Mark Beierl Date: Wed May 10 13:55:55 2023 -0400 Update to Python 3.10 and Ubuntu 22.04 Removed stale test file that has linting errors Removed event loops Updated Python dependencies Change-Id: I9462b0d67ea6b5bd4c869b5f2bc8d6c57d78660c Signed-off-by: Mark Beierl commit 9632c1ae3dadb73cf2f8af56e78f1363a977a1e2 Author: garciadeblas Date: Tue Apr 18 14:42:40 2023 +0200 Clean stage-archive.sh and use allowlist_externals in tox.ini Change-Id: I214df1372915a96db81ba36faff93dabffe18b6b Signed-off-by: garciadeblas commit e88401b595fe816b34308f1960aa7b545590f5dc Author: Gabriel Cuba Date: Wed Apr 5 15:24:52 2023 -0500 Feature 10975: adds vim-flavor-id to ns_instantiate_vdu schema Change-Id: Ib638fa9d29f3899bcc4609634d3a99e485152e5d Signed-off-by: Gabriel Cuba commit 9af2a4785d3a77772fd205aa572cc6a64d4d1003 Author: Gulsum Atici Date: Tue Mar 28 17:50:48 2023 +0300 Fix Bug 2229 Set fixed IP address for VDU through VNFD and the instantiation params Change-Id: Ia912cd52a0965a6c2b23faa2b88d9b4d0569fd3f Signed-off-by: Gulsum Atici commit 120105b5746ab35c004e523aaada39dc8d517888 Author: garciadeblas Date: Wed Feb 22 16:52:24 2023 +0100 Use ip_profile_schema in validation.py Change-Id: If5742f94acba919d5400fabc4c601e45b05c1bdb Signed-off-by: garciadeblas commit 4cd875d2a38488b5e717258d548eeb8e557ec9a8 Author: garciadeblas Date: Tue Feb 14 19:05:34 2023 +0100 Replace yaml.load by yaml.safe_load Change-Id: I4f6c3802e40d763fc2175dbb2bd94dbc79b813c2 Signed-off-by: garciadeblas Change-Id: I964dfd4f263ba6c15553ffb925ff0174835d7368 Signed-off-by: Dario Faccin --- Dockerfile | 14 ++++---- {osm_nbi/tests => attic}/run_test.py | 7 ++-- devops-stages/stage-archive.sh | 5 +-- osm_nbi/auth.py | 2 +- osm_nbi/descriptor_topics.py | 2 +- osm_nbi/engine.py | 2 +- osm_nbi/instance_topics.py | 6 ++-- osm_nbi/nbi.py | 20 +++++------ osm_nbi/notifications.py | 15 ++++---- osm_nbi/subscriptions.py | 47 +++++++++---------------- osm_nbi/tests/test_admin_topics.py | 9 +++-- osm_nbi/tests/test_instance_topics.py | 50 ++++++++++++--------------- osm_nbi/tests/test_osm_vnfm.py | 28 +++++++-------- osm_nbi/tests/test_pmjobs_topic.py | 20 +++++------ osm_nbi/validation.py | 18 ++-------- pyangbind.patch | 46 ++++++++++++++++++++++++ requirements-dev.txt | 16 +++++---- requirements-test.txt | 12 +++---- requirements.txt | 33 ++++++++---------- tox.ini | 10 +++--- 20 files changed, 185 insertions(+), 177 deletions(-) rename {osm_nbi/tests => attic}/run_test.py (99%) create mode 100644 pyangbind.patch diff --git a/Dockerfile b/Dockerfile index 2a64fdc..c4c9b6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,7 @@ # devops-stages/stage-build.sh # -FROM ubuntu:20.04 +FROM ubuntu:22.04 ARG APT_PROXY RUN if [ ! -z $APT_PROXY ] ; then \ @@ -34,13 +34,15 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \ debhelper \ dh-python \ git \ - python3.8 \ + python3 \ python3-all \ - python3.8-dev \ - python3-setuptools + python3-dev \ + python3-setuptools \ + python3-pip \ + tox -RUN python3 -m easy_install pip==21.3.1 -RUN pip install tox==3.24.5 +ENV LC_ALL C.UTF-8 +ENV LANG C.UTF-8 RUN DEBIAN_FRONTEND=noninteractive apt-get -y install wget diff --git a/osm_nbi/tests/run_test.py b/attic/run_test.py similarity index 99% rename from osm_nbi/tests/run_test.py rename to attic/run_test.py index 02141f5..b7768ba 100755 --- a/osm_nbi/tests/run_test.py +++ b/attic/run_test.py @@ -2781,7 +2781,7 @@ class TestDeploy: ns_data.update(self.ns_params) if test_params and test_params.get("ns-config"): if isinstance(test_params["ns-config"], str): - ns_data.update(yaml.load(test_params["ns-config"]), Loader=yaml.Loader) + ns_data.update(yaml.safe_load(test_params["ns-config"])) else: ns_data.update(test_params["ns-config"]) self.instantiate(engine, ns_data) @@ -3347,7 +3347,7 @@ class TestDeployHackfest3Charmed3(TestDeployHackfest3Charmed): "2": ["ls -lrt /home/ubuntu/first-touch-2"], } self.descriptor_edit = { - "vnfd0": yaml.load( + "vnfd0": yaml.safe_load( """ scaling-group-descriptor: - name: "scale_dataVM" @@ -3397,7 +3397,6 @@ class TestDeployHackfest3Charmed3(TestDeployHackfest3Charmed): "$[0]": default-value: "" """, - Loader=yaml.Loader, ) } self.ns_params = { @@ -3810,7 +3809,7 @@ class TestDeployHnfd(TestDeployHackfest3Charmed): } if test_params and test_params.get("ns-config"): if isinstance(test_params["ns-config"], str): - ns_data.update(yaml.load(test_params["ns-config"]), Loader=yaml.Loader) + ns_data.update(yaml.safe_load(test_params["ns-config"])) else: ns_data.update(test_params["ns-config"]) diff --git a/devops-stages/stage-archive.sh b/devops-stages/stage-archive.sh index 36d341f..0c1e93c 100755 --- a/devops-stages/stage-archive.sh +++ b/devops-stages/stage-archive.sh @@ -18,7 +18,4 @@ rm -rf pool rm -rf dists mkdir -p pool/$MDG mv deb_dist/*.deb pool/$MDG/ -mkdir -p dists/unstable/$MDG/binary-amd64/ -apt-ftparchive packages pool/$MDG > dists/unstable/$MDG/binary-amd64/Packages -gzip -9fk dists/unstable/$MDG/binary-amd64/Packages -echo "dists/**,pool/$MDG/*.deb" + diff --git a/osm_nbi/auth.py b/osm_nbi/auth.py index 139c165..0b3264f 100644 --- a/osm_nbi/auth.py +++ b/osm_nbi/auth.py @@ -283,7 +283,7 @@ class Authenticator: (r for r in records if r["name"] == "system_admin"), None ): with open(self.roles_to_operations_file, "r") as stream: - roles_to_operations_yaml = yaml.load(stream, Loader=yaml.Loader) + roles_to_operations_yaml = yaml.safe_load(stream) role_names = [] for role_with_operations in roles_to_operations_yaml["roles"]: diff --git a/osm_nbi/descriptor_topics.py b/osm_nbi/descriptor_topics.py index fc85b43..ca10c42 100644 --- a/osm_nbi/descriptor_topics.py +++ b/osm_nbi/descriptor_topics.py @@ -437,7 +437,7 @@ class DescriptorTopic(BaseTopic): indata = json.load(content) else: error_text = "Invalid yaml format " - indata = yaml.load(content, Loader=yaml.SafeLoader) + indata = yaml.safe_load(content) # Need to close the file package here so it can be copied from the # revision to the current, unrevisioned record diff --git a/osm_nbi/engine.py b/osm_nbi/engine.py index e9b1549..9b17402 100644 --- a/osm_nbi/engine.py +++ b/osm_nbi/engine.py @@ -205,7 +205,7 @@ class Engine(object): # "resources_to_operations file missing") # # with open(resources_to_operations_file, 'r') as f: - # resources_to_operations = yaml.load(f, Loader=yaml.Loader) + # resources_to_operations = yaml.safeload(f) # # self.operations = [] # diff --git a/osm_nbi/instance_topics.py b/osm_nbi/instance_topics.py index 060e056..f553d64 100644 --- a/osm_nbi/instance_topics.py +++ b/osm_nbi/instance_topics.py @@ -886,7 +886,7 @@ class NsrTopic(BaseTopic): # Name, mac-address and interface position is taken from VNFD # and included into VNFR. By this way RO can process this information # while creating the VDU. - iface_fields = ("name", "mac-address", "position") + iface_fields = ("name", "mac-address", "position", "ip-address") vdu_iface = { x: iface[x] for x in iface_fields if iface.get(x) is not None } @@ -1537,8 +1537,8 @@ class NsLcmOpTopic(BaseTopic): ivld.get("id"): set() for ivld in get_iterable(vnfd.get("int-virtual-link-desc")) } - for vdu in get_iterable(vnfd.get("vdu")): - for cpd in get_iterable(vnfd.get("int-cpd")): + for vdu in vnfd.get("vdu", {}): + for cpd in vdu.get("int-cpd", {}): if cpd.get("int-virtual-link-desc"): vnfd_ivlds_cpds[cpd.get("int-virtual-link-desc")] = cpd.get("id") diff --git a/osm_nbi/nbi.py b/osm_nbi/nbi.py index fed3205..1cd13b7 100644 --- a/osm_nbi/nbi.py +++ b/osm_nbi/nbi.py @@ -673,9 +673,7 @@ class Server(object): cherrypy.request.headers.pop("Content-File-MD5", None) elif "application/yaml" in cherrypy.request.headers["Content-Type"]: error_text = "Invalid yaml format " - indata = yaml.load( - cherrypy.request.body, Loader=yaml.SafeLoader - ) + indata = yaml.safe_load(cherrypy.request.body) cherrypy.request.headers.pop("Content-File-MD5", None) elif ( "application/binary" in cherrypy.request.headers["Content-Type"] @@ -705,13 +703,11 @@ class Server(object): # "Only 'Content-Type' of type 'application/json' or # 'application/yaml' for input format are available") error_text = "Invalid yaml format " - indata = yaml.load( - cherrypy.request.body, Loader=yaml.SafeLoader - ) + indata = yaml.safe_load(cherrypy.request.body) cherrypy.request.headers.pop("Content-File-MD5", None) else: error_text = "Invalid yaml format " - indata = yaml.load(cherrypy.request.body, Loader=yaml.SafeLoader) + indata = yaml.safe_load(cherrypy.request.body) cherrypy.request.headers.pop("Content-File-MD5", None) if not indata: indata = {} @@ -726,7 +722,7 @@ class Server(object): kwargs[k] = None elif format_yaml: try: - kwargs[k] = yaml.load(v, Loader=yaml.SafeLoader) + kwargs[k] = yaml.safe_load(v) except Exception: pass elif ( @@ -750,7 +746,7 @@ class Server(object): v[index] = None elif format_yaml: try: - v[index] = yaml.load(v[index], Loader=yaml.SafeLoader) + v[index] = yaml.safe_load(v[index]) except Exception: pass @@ -978,7 +974,7 @@ class Server(object): return self._format_out(str(alarm_list)) # to handle patch request for alarm update elif cherrypy.request.method == "PATCH": - data = yaml.load(cherrypy.request.body, Loader=yaml.SafeLoader) + data = yaml.safe_load(cherrypy.request.body) try: # check if uuid is valid self.engine.db.get_one("alarms", {"uuid": data.get("uuid")}) @@ -1172,13 +1168,13 @@ class Server(object): return_text = "
{} ->\n".format(main_topic)
             try:
                 if cherrypy.request.method == "POST":
-                    to_send = yaml.load(cherrypy.request.body, Loader=yaml.SafeLoader)
+                    to_send = yaml.safe_load(cherrypy.request.body)
                     for k, v in to_send.items():
                         self.engine.msg.write(main_topic, k, v)
                         return_text += "  {}: {}\n".format(k, v)
                 elif cherrypy.request.method == "GET":
                     for k, v in kwargs.items():
-                        v_dict = yaml.load(v, Loader=yaml.SafeLoader)
+                        v_dict = yaml.safe_load(v)
                         self.engine.msg.write(main_topic, k, v_dict)
                         return_text += "  {}: {}\n".format(k, v_dict)
             except Exception as e:
diff --git a/osm_nbi/notifications.py b/osm_nbi/notifications.py
index a62670b..63d4ce8 100644
--- a/osm_nbi/notifications.py
+++ b/osm_nbi/notifications.py
@@ -108,12 +108,12 @@ class NotificationBase:
         return payload
 
     async def send_notifications(
-        self, subscribers: list, loop: asyncio.AbstractEventLoop = None
+        self,
+        subscribers: list,
     ):
         """
         Generate tasks for all notification for an event.
         :param subscribers: A list of subscribers who want to be notified for event.
-        :param loop: Event loop object.
         """
         notifications = []
         for subscriber in subscribers:
@@ -154,21 +154,19 @@ class NotificationBase:
 
         if notifications:
             tasks = []
-            async with aiohttp.ClientSession(loop=loop) as session:
+            async with aiohttp.ClientSession() as session:
                 for notification in notifications:
                     tasks.append(
                         asyncio.ensure_future(
-                            self.send_notification(session, notification, loop=loop),
-                            loop=loop,
+                            self.send_notification(session, notification),
                         )
                     )
-                await asyncio.gather(*tasks, loop=loop)
+                await asyncio.gather(*tasks)
 
     async def send_notification(
         self,
         session: aiohttp.ClientSession,
         notification: dict,
-        loop: asyncio.AbstractEventLoop = None,
         retry_count: int = 5,
         timeout: float = 5.0,
     ):
@@ -177,7 +175,6 @@ class NotificationBase:
         after maximum number of reties, then notification is dropped.
         :param session: An aiohttp client session object to maintain http session.
         :param notification: A dictionary containing all necessary data to make POST request.
-        :param loop: Event loop object.
         :param retry_count: An integer specifying the maximum number of reties for a notification.
         :param timeout: A float representing client timeout of each HTTP request.
         """
@@ -226,7 +223,7 @@ class NotificationBase:
                         notification["payload"]["subscriptionId"], backoff_delay
                     )
                 )
-                await asyncio.sleep(backoff_delay, loop=loop)
+                await asyncio.sleep(backoff_delay)
         # Dropping notification
         self.logger.debug(
             "Notification {} sent failed to subscriber:{}.".format(
diff --git a/osm_nbi/subscriptions.py b/osm_nbi/subscriptions.py
index b178e5b..846e7d3 100644
--- a/osm_nbi/subscriptions.py
+++ b/osm_nbi/subscriptions.py
@@ -53,7 +53,6 @@ class SubscriptionThread(threading.Thread):
         self.db = None
         self.msg = None
         self.engine = engine
-        self.loop = None
         self.logger = logging.getLogger("nbi.subscriptions")
         self.aiomain_task_admin = (
             None  # asyncio task for receiving admin actions from kafka bus
@@ -81,41 +80,38 @@ class SubscriptionThread(threading.Thread):
                 # created.
                 # Before subscribe, send dummy messages
                 await self.msg.aiowrite(
-                    "admin", "echo", "dummy message", loop=self.loop
+                    "admin",
+                    "echo",
+                    "dummy message",
                 )
-                await self.msg.aiowrite("ns", "echo", "dummy message", loop=self.loop)
-                await self.msg.aiowrite("nsi", "echo", "dummy message", loop=self.loop)
-                await self.msg.aiowrite("vnf", "echo", "dummy message", loop=self.loop)
+                await self.msg.aiowrite("ns", "echo", "dummy message")
+                await self.msg.aiowrite("nsi", "echo", "dummy message")
+                await self.msg.aiowrite("vnf", "echo", "dummy message")
                 if not kafka_working:
                     self.logger.critical("kafka is working again")
                     kafka_working = True
                 if not self.aiomain_task_admin:
-                    await asyncio.sleep(10, loop=self.loop)
+                    await asyncio.sleep(10)
                     self.logger.debug("Starting admin subscription task")
                     self.aiomain_task_admin = asyncio.ensure_future(
                         self.msg.aioread(
                             ("admin",),
-                            loop=self.loop,
                             group_id=False,
                             aiocallback=self._msg_callback,
                         ),
-                        loop=self.loop,
                     )
                 if not self.aiomain_task:
-                    await asyncio.sleep(10, loop=self.loop)
+                    await asyncio.sleep(10)
                     self.logger.debug("Starting non-admin subscription task")
                     self.aiomain_task = asyncio.ensure_future(
                         self.msg.aioread(
                             ("ns", "nsi", "vnf"),
-                            loop=self.loop,
                             aiocallback=self._msg_callback,
                         ),
-                        loop=self.loop,
                     )
                 done, _ = await asyncio.wait(
                     [self.aiomain_task, self.aiomain_task_admin],
                     timeout=None,
-                    loop=self.loop,
                     return_when=asyncio.FIRST_COMPLETED,
                 )
                 try:
@@ -142,14 +138,13 @@ class SubscriptionThread(threading.Thread):
                         "Error accessing kafka '{}'. Retrying ...".format(e)
                     )
                     kafka_working = False
-            await asyncio.sleep(10, loop=self.loop)
+            await asyncio.sleep(10)
 
     def run(self):
         """
         Start of the thread
         :return: None
         """
-        self.loop = asyncio.new_event_loop()
         try:
             if not self.db:
                 if self.config["database"]["driver"] == "mongo":
@@ -166,7 +161,6 @@ class SubscriptionThread(threading.Thread):
                     )
             if not self.msg:
                 config_msg = self.config["message"].copy()
-                config_msg["loop"] = self.loop
                 if config_msg["driver"] == "local":
                     self.msg = msglocal.MsgLocal()
                     self.msg.connect(config_msg)
@@ -187,11 +181,7 @@ class SubscriptionThread(threading.Thread):
         self.logger.debug("Starting")
         while not self.to_terminate:
             try:
-                self.loop.run_until_complete(
-                    asyncio.ensure_future(self.start_kafka(), loop=self.loop)
-                )
-            # except asyncio.CancelledError:
-            #     break  # if cancelled it should end, breaking loop
+                asyncio.run(self.start_kafka())
             except Exception as e:
                 if not self.to_terminate:
                     self.logger.exception(
@@ -200,7 +190,6 @@ class SubscriptionThread(threading.Thread):
 
         self.logger.debug("Finishing")
         self._stop()
-        self.loop.close()
 
     async def _msg_callback(self, topic, command, params):
         """
@@ -265,10 +254,7 @@ class SubscriptionThread(threading.Thread):
                             # self.logger.debug(subscribers)
                             if subscribers:
                                 asyncio.ensure_future(
-                                    self.nslcm.send_notifications(
-                                        subscribers, loop=self.loop
-                                    ),
-                                    loop=self.loop,
+                                    self.nslcm.send_notifications(subscribers),
                                 )
                 else:
                     self.logger.debug(
@@ -296,8 +282,7 @@ class SubscriptionThread(threading.Thread):
                     )
                     if subscribers:
                         asyncio.ensure_future(
-                            self.vnflcm.send_notifications(subscribers, loop=self.loop),
-                            loop=self.loop,
+                            self.vnflcm.send_notifications(subscribers),
                         )
             elif topic == "nsi":
                 if command == "terminated" and params["operationState"] in (
@@ -343,7 +328,7 @@ class SubscriptionThread(threading.Thread):
             # writing to kafka must be done with our own loop. For this reason it is not allowed Engine to do that,
             # but content to be written is stored at msg_to_send
             for msg in msg_to_send:
-                await self.msg.aiowrite(*msg, loop=self.loop)
+                await self.msg.aiowrite(*msg)
         except (EngineException, DbException, MsgException) as e:
             self.logger.error(
                 "Error while processing topic={} command={}: {}".format(
@@ -379,6 +364,8 @@ class SubscriptionThread(threading.Thread):
         """
         self.to_terminate = True
         if self.aiomain_task:
-            self.loop.call_soon_threadsafe(self.aiomain_task.cancel)
+            asyncio.get_event_loop().call_soon_threadsafe(self.aiomain_task.cancel)
         if self.aiomain_task_admin:
-            self.loop.call_soon_threadsafe(self.aiomain_task_admin.cancel)
+            asyncio.get_event_loop().call_soon_threadsafe(
+                self.aiomain_task_admin.cancel
+            )
diff --git a/osm_nbi/tests/test_admin_topics.py b/osm_nbi/tests/test_admin_topics.py
index 57551c7..938ab93 100755
--- a/osm_nbi/tests/test_admin_topics.py
+++ b/osm_nbi/tests/test_admin_topics.py
@@ -18,12 +18,12 @@ __author__ = "Pedro de la Cruz Ramos, pedro.delacruzramos@altran.com"
 __date__ = "$2019-10-019"
 
 import unittest
+import random
 from unittest import TestCase
 from unittest.mock import Mock, patch, call, ANY
 from uuid import uuid4
 from http import HTTPStatus
 from time import time
-from random import randint
 from osm_common import dbbase, fsbase, msgbase
 from osm_nbi import authconn, validation
 from osm_nbi.admin_topics import (
@@ -241,7 +241,10 @@ class Test_ProjectTopicAuth(TestCase):
         with self.subTest(i=1):
             self.auth.get_project_list.side_effect = [[proj], []]
             new_name = "new-project-name"
-            quotas = {"vnfds": randint(0, 100), "nsds": randint(0, 100)}
+            quotas = {
+                "vnfds": random.SystemRandom().randint(0, 100),
+                "nsds": random.SystemRandom().randint(0, 100),
+            }
             self.topic.edit(
                 self.fake_session, pid, {"name": new_name, "quotas": quotas}
             )
@@ -256,7 +259,7 @@ class Test_ProjectTopicAuth(TestCase):
             self.assertEqual(content["quotas"], quotas, "Wrong quotas")
         with self.subTest(i=2):
             new_name = "other-project-name"
-            quotas = {"baditems": randint(0, 100)}
+            quotas = {"baditems": random.SystemRandom().randint(0, 100)}
             self.auth.get_project_list.side_effect = [[proj], []]
             with self.assertRaises(EngineException, msg="Accepted wrong quotas") as e:
                 self.topic.edit(
diff --git a/osm_nbi/tests/test_instance_topics.py b/osm_nbi/tests/test_instance_topics.py
index 96da68c..a883bdc 100644
--- a/osm_nbi/tests/test_instance_topics.py
+++ b/osm_nbi/tests/test_instance_topics.py
@@ -49,13 +49,11 @@ class TestNsLcmOpTopic(unittest.TestCase):
         self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
         self.nslcmop_topic.check_quota = Mock(return_value=None)  # skip quota
 
-        self.db.create_list(
-            "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
-        )
-        self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
-        self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader))
-        self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
-        self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+        self.db.create_list("vim_accounts", yaml.safe_load(db_vim_accounts_text))
+        self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
+        self.db.create_list("vnfds", yaml.safe_load(db_vnfds_text))
+        self.db.create_list("vnfrs", yaml.safe_load(db_vnfrs_text))
+        self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
         self.db.create = Mock(return_value="created_id")
         self.nsd = self.db.get_list("nsds")[0]
         self.nsd_id = self.nsd["_id"]
@@ -389,8 +387,8 @@ class TestNsLcmOpTopicWithMock(unittest.TestCase):
         self.nslcmop_topic = NsLcmOpTopic(self.db, self.fs, self.msg, None)
 
     def test_get_vnfd_from_vnf_member_revision(self):
-        test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)[0]
-        test_vnfd = yaml.load(db_vnfds_text, Loader=yaml.Loader)
+        test_vnfr = yaml.safe_load(db_vnfrs_text)[0]
+        test_vnfd = yaml.safe_load(db_vnfds_text)
         self.db.get_one.side_effect = [test_vnfr, test_vnfd]
         _ = self.nslcmop_topic._get_vnfd_from_vnf_member_index("1", test_vnfr["_id"])
         self.assertEqual(
@@ -405,9 +403,9 @@ class TestNsLcmOpTopicWithMock(unittest.TestCase):
         )
 
     def test_get_vnfd_from_vnf_member_no_revision(self):
-        test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)[0]
+        test_vnfr = yaml.safe_load(db_vnfrs_text)[0]
         test_vnfr["revision"] = 3
-        test_vnfd = yaml.load(db_vnfds_text, Loader=yaml.Loader)
+        test_vnfd = yaml.safe_load(db_vnfds_text)
         self.db.get_one.side_effect = [test_vnfr, test_vnfd]
         _ = self.nslcmop_topic._get_vnfd_from_vnf_member_index("1", test_vnfr["_id"])
         self.assertEqual(
@@ -434,9 +432,9 @@ class TestNsLcmOpTopicWithMock(unittest.TestCase):
         session = {}
 
         with self.subTest(i=1, t="VNF instance does not belong to NS"):
-            test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
+            test_vnfr = yaml.safe_load(db_vnfrs_text)
             test_vnfr[0]["revision"] = 2
-            test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
+            test_nsr = yaml.safe_load(db_nsrs_text)
             test_nsr[0]["constituent-vnfr-ref"][
                 0
             ] = "99d90b0c-faff-4b9f-bccd-017f33985984"
@@ -460,9 +458,9 @@ class TestNsLcmOpTopicWithMock(unittest.TestCase):
             )
 
         with self.subTest(i=2, t="Ns update request validated with no exception"):
-            test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
+            test_vnfr = yaml.safe_load(db_vnfrs_text)
             test_vnfr[0]["revision"] = 2
-            test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
+            test_nsr = yaml.safe_load(db_nsrs_text)
             self.db.create_list("vnfrs", test_vnfr)
             self.db.create_list("nsrs", test_nsr)
             nsrs = self.db.get_list("nsrs")[1]
@@ -498,9 +496,9 @@ class TestNsLcmOpTopicWithMock(unittest.TestCase):
             )
 
         with self.subTest(i=4, t="wrong vnfdid is given as an update parameter"):
-            test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
+            test_vnfr = yaml.safe_load(db_vnfrs_text)
             test_vnfr[0]["revision"] = 2
-            test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
+            test_nsr = yaml.safe_load(db_nsrs_text)
             self.db.create_list("vnfrs", test_vnfr)
             self.db.create_list("nsrs", test_nsr)
             nsrs = self.db.get_list("nsrs")[2]
@@ -524,9 +522,9 @@ class TestNsLcmOpTopicWithMock(unittest.TestCase):
         with self.subTest(
             i=5, t="Ns update REMOVE_VNF request validated with no exception"
         ):
-            test_vnfr = yaml.load(db_vnfrs_text, Loader=yaml.Loader)
+            test_vnfr = yaml.safe_load(db_vnfrs_text)
             test_vnfr[0]["revision"] = 2
-            test_nsr = yaml.load(db_nsrs_text, Loader=yaml.Loader)
+            test_nsr = yaml.safe_load(db_nsrs_text)
             self.db.create_list("vnfrs", test_vnfr)
             self.db.create_list("nsrs", test_nsr)
             nsrs = self.db.get_list("nsrs")[1]
@@ -550,11 +548,9 @@ class TestNsrTopic(unittest.TestCase):
         self.nsr_topic = NsrTopic(self.db, self.fs, self.msg, None)
         self.nsr_topic.check_quota = Mock(return_value=None)  # skip quota
 
-        self.db.create_list(
-            "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
-        )
-        self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
-        self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader))
+        self.db.create_list("vim_accounts", yaml.safe_load(db_vim_accounts_text))
+        self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
+        self.db.create_list("vnfds", yaml.safe_load(db_vnfds_text))
         self.db.create = Mock(return_value="created_id")
         self.nsd = self.db.get_list("nsds")[0]
         self.nsd_id = self.nsd["_id"]
@@ -722,7 +718,7 @@ class TestNsrTopic(unittest.TestCase):
         }
         filter_q = {}
         for refresh_status in ("true", "false"):
-            self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+            self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
             actual_nsr = self.db.get_list("nsrs")[0]
             nsr_id = actual_nsr["_id"]
             filter_q["vcaStatus-refresh"] = refresh_status
@@ -744,7 +740,7 @@ class TestNsrTopic(unittest.TestCase):
         }
         filter_q = {"vcaStatus-refresh": "true"}
         time_delta = 120
-        self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+        self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
         nsr = self.db.get_list("nsrs")[0]
 
         # When vcaStatus-refresh is true
@@ -779,7 +775,7 @@ class TestNsrTopic(unittest.TestCase):
         )
 
     def test_delete_ns(self):
-        self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+        self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
         self.nsr = self.db.get_list("nsrs")[0]
         self.nsr_id = self.nsr["_id"]
         self.db_set_one = self.db.set_one
diff --git a/osm_nbi/tests/test_osm_vnfm.py b/osm_nbi/tests/test_osm_vnfm.py
index c3947b9..e46e99b 100644
--- a/osm_nbi/tests/test_osm_vnfm.py
+++ b/osm_nbi/tests/test_osm_vnfm.py
@@ -41,10 +41,8 @@ class TestVnfInstances(unittest.TestCase):
         self.msg = Mock(MsgBase())
         self.vnfinstances = VnfInstances(self.db, self.fs, self.msg, None)
         self.nsrtopic = NsrTopic(self.db, self.fs, self.msg, None)
-        self.db.create_list(
-            "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
-        )
-        self.db.create_list("vnfds", yaml.load(db_vnfm_vnfd_text, Loader=yaml.Loader))
+        self.db.create_list("vim_accounts", yaml.safe_load(db_vim_accounts_text))
+        self.db.create_list("vnfds", yaml.safe_load(db_vnfm_vnfd_text))
         self.vnfd = self.db.get_list("vnfds")[0]
         self.vnfd_id = self.vnfd["id"]
         self.vnfd_project = self.vnfd["_admin"]["projects_read"][0]
@@ -107,7 +105,7 @@ class TestVnfInstances(unittest.TestCase):
             "method": "write",
         }
         filter_q = {}
-        self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
+        self.db.create_list("vnfrs", yaml.safe_load(db_vnfrs_text))
         actual_vnfr = self.db.get_list("vnfrs")[0]
         id = actual_vnfr["_id"]
         expected_vnfr = self.vnfinstances.show(session, id, filter_q)
@@ -125,9 +123,9 @@ class TestVnfInstances(unittest.TestCase):
             "project_id": [self.vnfd_project],
             "method": "delete",
         }
-        self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
-        self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
-        self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
+        self.db.create_list("vnfrs", yaml.safe_load(db_vnfrs_text))
+        self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
+        self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
 
         self.vnfr = self.db.get_list("vnfrs")[0]
         self.vnfr_id = self.vnfr["_id"]
@@ -150,13 +148,11 @@ class TestVnfLcmOpTopic(unittest.TestCase):
         self.vnflcmop_topic = VnfLcmOpTopic(self.db, self.fs, self.msg, None)
         self.vnflcmop_topic.check_quota = Mock(return_value=None)  # skip quota
 
-        self.db.create_list(
-            "vim_accounts", yaml.load(db_vim_accounts_text, Loader=yaml.Loader)
-        )
-        self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
-        self.db.create_list("vnfds", yaml.load(db_vnfm_vnfd_text, Loader=yaml.Loader))
-        self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
-        self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+        self.db.create_list("vim_accounts", yaml.safe_load(db_vim_accounts_text))
+        self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
+        self.db.create_list("vnfds", yaml.safe_load(db_vnfm_vnfd_text))
+        self.db.create_list("vnfrs", yaml.safe_load(db_vnfrs_text))
+        self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
 
         self.vnfd = self.db.get_list("vnfds")[0]
         self.vnfd_id = self.vnfd["_id"]
@@ -208,7 +204,7 @@ class TestVnfLcmOpTopic(unittest.TestCase):
             "project_id": [self.vnfd_project],
             "method": "write",
         }
-        self.db.create_list("nslcmops", yaml.load(db_nslcmops_text, Loader=yaml.Loader))
+        self.db.create_list("nslcmops", yaml.safe_load(db_nslcmops_text))
         filter_q = {}
         actual_lcmop = self.db.get_list("nslcmops")[0]
         id = actual_lcmop["_id"]
diff --git a/osm_nbi/tests/test_pmjobs_topic.py b/osm_nbi/tests/test_pmjobs_topic.py
index 231818b..e5605c3 100644
--- a/osm_nbi/tests/test_pmjobs_topic.py
+++ b/osm_nbi/tests/test_pmjobs_topic.py
@@ -43,10 +43,10 @@ class PmJobsTopicTest(asynctest.TestCase):
     def setUp(self):
         self.db = DbMemory()
         self.pmjobs_topic = PmJobsTopic(self.db, host="prometheus", port=9091)
-        self.db.create_list("nsds", yaml.load(db_nsds_text, Loader=yaml.Loader))
-        self.db.create_list("vnfds", yaml.load(db_vnfds_text, Loader=yaml.Loader))
-        self.db.create_list("vnfrs", yaml.load(db_vnfrs_text, Loader=yaml.Loader))
-        self.db.create_list("nsrs", yaml.load(db_nsrs_text, Loader=yaml.Loader))
+        self.db.create_list("nsds", yaml.safe_load(db_nsds_text))
+        self.db.create_list("vnfds", yaml.safe_load(db_vnfds_text))
+        self.db.create_list("vnfrs", yaml.safe_load(db_vnfrs_text))
+        self.db.create_list("nsrs", yaml.safe_load(db_nsrs_text))
         self.nsr = self.db.get_list("nsrs")[0]
         self.nsr_id = self.nsr["_id"]
         project_id = self.nsr["_admin"]["projects_write"]
@@ -80,18 +80,18 @@ class PmJobsTopicTest(asynctest.TestCase):
         for metric in metric_list:
             endpoint = re.sub(r"metric_name", metric, site)
             if metric == "cpu_utilization":
-                response = yaml.load(cpu_utilization, Loader=yaml.Loader)
+                response = yaml.safe_load(cpu_utilization)
             elif metric == "users":
-                response = yaml.load(users, Loader=yaml.Loader)
+                response = yaml.safe_load(users)
             elif metric == "load":
-                response = yaml.load(load, Loader=yaml.Loader)
+                response = yaml.safe_load(load)
             else:
-                response = yaml.load(empty, Loader=yaml.Loader)
+                response = yaml.safe_load(empty)
             mock_res.get(endpoint, payload=response)
 
     async def test_prom_metric_request(self):
         with self.subTest("Test case1 failed in test_prom"):
-            prom_response = yaml.load(prom_res, Loader=yaml.Loader)
+            prom_response = yaml.safe_load(prom_res)
             with aioresponses() as mock_res:
                 self.set_get_mock_res(mock_res, self.nsr_id, self.metric_check_list)
                 result = await self.pmjobs_topic._prom_metric_request(
@@ -109,7 +109,7 @@ class PmJobsTopicTest(asynctest.TestCase):
 
     def test_show(self):
         with self.subTest("Test case1 failed in test_show"):
-            show_response = yaml.load(show_res, Loader=yaml.Loader)
+            show_response = yaml.safe_load(show_res)
             with aioresponses() as mock_res:
                 self.set_get_mock_res(mock_res, self.nsr_id, self.metric_check_list)
                 result = self.pmjobs_topic.show(self.session, self.nsr_id)
diff --git a/osm_nbi/validation.py b/osm_nbi/validation.py
index 4228346..8b93566 100644
--- a/osm_nbi/validation.py
+++ b/osm_nbi/validation.py
@@ -140,6 +140,7 @@ ns_instantiate_vdu = {
         "configurable-properties": {
             "type": "object",
         },
+        "vim-flavor-id": name_schema,
         "volume": {
             "type": "array",
             "minItems": 1,
@@ -197,19 +198,6 @@ ip_profile_dhcp_schema = {
 }
 
 ip_profile_schema = {
-    "title": "ip profile validation schema",
-    "$schema": "http://json-schema.org/draft-04/schema#",
-    "type": "object",
-    "properties": {
-        "ip-version": {"enum": ["ipv4", "ipv6"]},
-        "subnet-address": ip_prefix_schema,
-        "gateway-address": ip_schema,
-        "dns-server": ip_profile_dns_schema,
-        "dhcp-params": ip_profile_dhcp_schema,
-    },
-}
-
-ip_profile_update_schema = {
     "title": "ip profile validation schema",
     "$schema": "http://json-schema.org/draft-04/schema#",
     "type": "object",
@@ -256,7 +244,7 @@ ns_instantiate_internal_vld = {
         "name": name_schema,
         "vim-network-name": name_schema,
         "vim-network-id": name_schema,
-        "ip-profile": ip_profile_update_schema,
+        "ip-profile": ip_profile_schema,
         "provider-network": provider_network_schema,
         "internal-connection-point": {
             "type": "array",
@@ -397,7 +385,7 @@ ns_instantiate = {
                     "vim-network-id": {"oneOf": [string_schema, object_schema]},
                     "ns-net": object_schema,
                     "wimAccountId": {"oneOf": [id_schema, bool_schema, null_schema]},
-                    "ip-profile": object_schema,
+                    "ip-profile": ip_profile_schema,
                     "provider-network": provider_network_schema,
                     "vnfd-connection-point-ref": {
                         "type": "array",
diff --git a/pyangbind.patch b/pyangbind.patch
new file mode 100644
index 0000000..3077299
--- /dev/null
+++ b/pyangbind.patch
@@ -0,0 +1,46 @@
+#######################################################################################
+# Copyright ETSI Contributors and Others.
+#
+# 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.
+#######################################################################################
+
+*** .tox/cover/lib/python3.10/site-packages/pyangbind/lib/yangtypes.py	2023-05-10 06:50:57.876027148 -0400
+--- .tox/cover/lib/python3.10/site-packages/pyangbind/lib/yangtypes.py	2023-05-10 06:51:11.772022417 -0400
+*************** limitations under the License.
+*** 22,27 ****
+--- 22,28 ----
+  from __future__ import unicode_literals
+
+  import collections
++ from six.moves import collections_abc
+  import copy
+  import uuid
+  from decimal import Decimal
+*************** def TypedListType(*args, **kwargs):
+*** 372,378 ****
+    if not isinstance(allowed_type, list):
+      allowed_type = [allowed_type]
+
+!   class TypedList(collections.MutableSequence):
+      _pybind_generated_by = "TypedListType"
+      _list = list()
+
+--- 373,379 ----
+    if not isinstance(allowed_type, list):
+      allowed_type = [allowed_type]
+
+!   class TypedList(collections_abc.MutableSequence):
+      _pybind_generated_by = "TypedListType"
+      _list = list()
+
diff --git a/requirements-dev.txt b/requirements-dev.txt
index 4fd95de..aafb45a 100644
--- a/requirements-dev.txt
+++ b/requirements-dev.txt
@@ -20,14 +20,18 @@ async-timeout==4.0.2
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
     #   aiokafka
-bitarray==2.6.2
+bitarray==2.7.3
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/IM.git;a=blob_plain;f=requirements.txt;hb=paas
     #   pyangbind
-charset-normalizer==3.0.1
+charset-normalizer==3.1.0
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
 dataclasses==0.6
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
+dnspython==2.3.0
+    # via
+    #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
+    #   pymongo
 enum34==1.1.10
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/IM.git;a=blob_plain;f=requirements.txt;hb=paas
@@ -41,13 +45,13 @@ lxml==4.9.2
     #   -r https://osm.etsi.org/gitweb/?p=osm/IM.git;a=blob_plain;f=requirements.txt;hb=paas
     #   pyang
     #   pyangbind
-motor==1.3.1
+motor==3.1.2
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
 osm-common @ git+https://osm.etsi.org/gerrit/osm/common.git@paas
     # via -r requirements-dev.in
 osm-im @ git+https://osm.etsi.org/gerrit/osm/IM.git@paas
     # via -r requirements-dev.in
-packaging==23.0
+packaging==23.1
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
     #   aiokafka
@@ -63,7 +67,7 @@ pyangbind==0.8.1
     # via -r https://osm.etsi.org/gitweb/?p=osm/IM.git;a=blob_plain;f=requirements.txt;hb=paas
 pycryptodome==3.17
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
-pymongo==3.13.0
+pymongo==4.3.3
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
     #   motor
@@ -75,7 +79,7 @@ pyyaml==5.4.1
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/IM.git;a=blob_plain;f=requirements.txt;hb=paas
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=paas
-regex==2022.10.31
+regex==2023.5.5
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/IM.git;a=blob_plain;f=requirements.txt;hb=paas
     #   pyangbind
diff --git a/requirements-test.txt b/requirements-test.txt
index bd996ee..3a83125 100644
--- a/requirements-test.txt
+++ b/requirements-test.txt
@@ -24,13 +24,13 @@ async-timeout==4.0.2
     # via aiohttp
 asynctest==0.13.0
     # via -r requirements-test.in
-attrs==22.2.0
+attrs==23.1.0
     # via aiohttp
-charset-normalizer==3.0.1
+charset-normalizer==3.1.0
     # via aiohttp
-coverage==7.2.1
+coverage==7.2.5
     # via -r requirements-test.in
-deepdiff==6.2.3
+deepdiff==6.3.0
     # via -r requirements-test.in
 frozenlist==1.3.3
     # via
@@ -42,11 +42,11 @@ multidict==6.0.4
     # via
     #   aiohttp
     #   yarl
-nose2==0.12.0
+nose2==0.13.0
     # via -r requirements-test.in
 ordered-set==4.1.0
     # via deepdiff
 orjson==3.8.7
     # via deepdiff
-yarl==1.8.2
+yarl==1.9.2
     # via aiohttp
diff --git a/requirements.txt b/requirements.txt
index f23a4e6..556ced3 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -20,15 +20,15 @@ aiosignal==1.3.1
     # via aiohttp
 async-timeout==4.0.2
     # via aiohttp
-attrs==22.2.0
+attrs==23.1.0
     # via
     #   aiohttp
     #   jsonschema
 autocommand==2.2.2
     # via jaraco-text
-certifi==2022.12.7
+certifi==2023.5.7
     # via requests
-charset-normalizer==3.0.1
+charset-normalizer==3.1.0
     # via
     #   aiohttp
     #   requests
@@ -41,7 +41,7 @@ debtcollector==2.5.0
     #   oslo-config
     #   oslo-utils
     #   python-keystoneclient
-deepdiff==6.2.3
+deepdiff==6.3.0
     # via -r requirements.in
 frozenlist==1.3.3
     # via
@@ -55,15 +55,13 @@ importlib-resources==5.12.0
     # via
     #   jaraco-text
     #   jsonschema
-inflect==6.0.2
+inflect==6.0.4
     # via jaraco-text
 iso8601==1.1.0
     # via
     #   keystoneauth1
     #   oslo-utils
-jaraco-classes==3.2.3
-    # via jaraco-collections
-jaraco-collections==3.8.0
+jaraco-collections==4.1.0
     # via cherrypy
 jaraco-context==4.3.0
     # via jaraco-text
@@ -82,10 +80,9 @@ more-itertools==9.1.0
     # via
     #   cheroot
     #   cherrypy
-    #   jaraco-classes
     #   jaraco-functools
     #   jaraco-text
-msgpack==1.0.4
+msgpack==1.0.5
     # via oslo-serialization
 multidict==6.0.4
     # via
@@ -116,7 +113,7 @@ oslo-utils==6.1.0
     # via
     #   oslo-serialization
     #   python-keystoneclient
-packaging==23.0
+packaging==23.1
     # via
     #   oslo-utils
     #   python-keystoneclient
@@ -128,11 +125,9 @@ pbr==5.11.1
     #   oslo-serialization
     #   python-keystoneclient
     #   stevedore
-pkgutil-resolve-name==1.3.10
-    # via jsonschema
 portend==3.1.0
     # via cherrypy
-pydantic==1.10.5
+pydantic==1.10.7
     # via inflect
 pyparsing==3.0.9
     # via oslo-utils
@@ -140,7 +135,7 @@ pyrsistent==0.19.3
     # via jsonschema
 python-keystoneclient==5.1.0
     # via -r requirements.in
-pytz==2022.7.1
+pytz==2023.3
     # via
     #   oslo-serialization
     #   oslo-utils
@@ -149,7 +144,7 @@ pyyaml==5.4.1
     # via
     #   -r requirements.in
     #   oslo-config
-requests==2.28.2
+requests==2.30.0
     # via
     #   -r requirements.in
     #   keystoneauth1
@@ -170,15 +165,15 @@ stevedore==5.0.0
     #   python-keystoneclient
 tacacs-plus==2.6
     # via -r requirements.in
-tempora==5.2.1
+tempora==5.2.2
     # via portend
 typing-extensions==4.5.0
     # via pydantic
-urllib3==1.26.14
+urllib3==2.0.2
     # via requests
 wrapt==1.15.0
     # via debtcollector
-yarl==1.8.2
+yarl==1.9.2
     # via aiohttp
 zc-lockfile==3.0.post1
     # via cherrypy
diff --git a/tox.ini b/tox.ini
index b26bb35..4c8fd06 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,7 +22,7 @@ toxworkdir = /tmp/.tox
 
 [testenv]
 usedevelop = True
-basepython = python3.8
+basepython = python3.10
 setenv = VIRTUAL_ENV={envdir}
          PYTHONDONTWRITEBYTECODE = 1
 deps =  -r{toxinidir}/requirements.txt
@@ -42,13 +42,15 @@ deps =  {[testenv]deps}
         -r{toxinidir}/requirements-dev.txt
         -r{toxinidir}/requirements-test.txt
 commands =
+        sh -c "patch {toxworkdir}/cover/lib/python3.10/site-packages/pyangbind/lib/yangtypes.py < pyangbind.patch"
         sh -c 'rm -f nosetests.xml'
         coverage erase
         nose2 -C --coverage osm_nbi -s osm_nbi/tests
+        sh -c "patch -R {toxworkdir}/cover/lib/python3.10/site-packages/pyangbind/lib/yangtypes.py < pyangbind.patch"
         coverage report --omit='*tests*'
         coverage html -d ./cover --omit='*tests*'
         coverage xml -o coverage.xml --omit=*tests*
-whitelist_externals = sh
+allowlist_externals = sh
 
 
 #######################################################################################
@@ -83,7 +85,7 @@ commands =
 [testenv:pip-compile]
 deps =  pip-tools==6.6.2
 skip_install = true
-whitelist_externals = bash
+allowlist_externals = bash
         [
 commands =
         - bash -c "for file in requirements*.in ; do \
@@ -107,7 +109,7 @@ commands =
         python3 setup.py --command-packages=stdeb.command sdist_dsc
         sh -c 'cd deb_dist/osm-nbi*/ && dpkg-buildpackage -rfakeroot -uc -us'
         sh -c 'rm osm_nbi/requirements.txt'
-whitelist_externals = sh
+allowlist_externals = sh
 
 #######################################################################################
 [flake8]
-- 
2.25.1