Update from master

Squashed commit of the following:

commit b5015160aca7f04f2b0fb35c87281c0ab480f429
Author: Pedro Escaleira <escaleira@av.it.pt>
Date:   Wed May 17 00:13:05 2023 +0100

    Bug 2246 fixed

    Change-Id: Ic35d131d4e44686de207b0a6acc3360e04306cb2
    Signed-off-by: Pedro Escaleira <escaleira@av.it.pt>

commit 01df3ee231471330760e03b013382464e773eee2
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date:   Thu May 11 11:07:54 2023 +0300

    Fix AttributeError caused by updated pymongo version

    AttributeError: 'Cursor' object has no attribute 'count' is fixed.

    Change-Id: Id1b9133376d5a7dcb3998c623163bb57dd5c534b
    Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>

commit 8f3ab9a82608ffe74e6fd5d0c532822412dbc88a
Author: k4.rahul <rahul.k4@tataelxsi.co.in>
Date:   Fri May 5 14:18:47 2023 +0530

    Coverity-CWE 22: Improper Limitation of a Pathname to a Restricted Directory ('Path Traversal')

    Coverity fix for 137960 Filesystem path, filename, or URI manipulation

    Change-Id: I0691a9f231d6b7019fe413c261f50262ea7fb923
    Signed-off-by: k4.rahul <rahul.k4@tataelxsi.co.in>

commit bc94e3403ebab364fff7603c1a353c793b52966e
Author: k4.rahul <rahul.k4@tataelxsi.co.in>
Date:   Fri May 5 15:52:47 2023 +0530

    Coverity-CWE 260: Password in Configuration File

    Hardcoded credentials in​ configuration file​
    remove from the cloud-config.txt file as it is not being used anywhere in the test case

    Change-Id: I101e4b9b6f48fa6d34822bc6f400552329f9aa18
    Signed-off-by: k4.rahul <rahul.k4@tataelxsi.co.in>

commit db28d4290a34ed1a7ac7a2ca10cab7eb34a55fd1
Author: garciadeblas <gerardo.garciadeblas@telefonica.com>
Date:   Wed May 10 16:26:55 2023 +0200

    Minor updates in Dockerfile

    Change-Id: Ia12406fef38b13c56ebec3be5bee53cd00441181
    Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>

commit 0edc5108ac7e584cac210ed6bae8b8ef09511388
Author: garciadeblas <gerardo.garciadeblas@telefonica.com>
Date:   Tue Apr 18 15:07:15 2023 +0200

    Clean stage-archive.sh and use allowlist_extenals in tox.ini

    Change-Id: I511cd5009563589f54899f667d779239745f2778
    Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>

commit a06b854f2b278aaee015fc1f76015895f8cf50c1
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date:   Tue May 9 13:42:13 2023 +0300

    Ubuntu 22.04 and Python 3.10 preparation

    Change-Id: I740202d48977467a0c2b2afb4b17bd7597331dee
    Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>

commit b2d732a70efa33e4bc478d351d64bc4adb4ea332
Author: k4.rahul <rahul.k4@tataelxsi.co.in>
Date:   Thu Apr 27 16:20:47 2023 +0530

    Coverity-CWE 476: NULL Pointer Dereference (137978 Bad use of null-like value)

    Coverity fix for Bad use of null-like value

    Change-Id: I7437c2b2aeeff25619b5405bcd7c962f3fbd70bb
    Signed-off-by: k4.rahul <rahul.k4@tataelxsi.co.in>

commit 09496abf441b0f3730f0288df161da1ca004be69
Author: Gabriel Cuba <gcuba@whitestack.com>
Date:   Tue Apr 4 01:57:17 2023 -0500

    Fix bug 2231: reverse_sync in fsmongo obtains file timestamp with UTC timezone instead of local timezone, so
    that filesystem and mongodb timestamps are correctly compared

    Change-Id: I0056026704a624329aae1ae52a45143d12f6dfdd
    Signed-off-by: Gabriel Cuba <gcuba@whitestack.com>

commit 76394efe9fbee088dddd1dc9d4da6f043c3959a5
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date:   Mon Jan 9 23:19:18 2023 +0300

    Feature 10950 Replace pycrypto with pycryptodome

    Remove the pycrypto library and change encrypt and decrypt methods to work with pycryptodome.
    Move encryption methods from N2VC to common.

    Change-Id: I12a5f6138664ab6ebb7100c82523e91750f05f14
    Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>

Change-Id: Iccf3fcafe14305099fcceef65efd6e3c57cf6d2f
Signed-off-by: Dario Faccin <dario.faccin@canonical.com>
diff --git a/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt b/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt
index 7a83e12..5c78ae3 100755
--- a/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt
+++ b/osm_common/tests/packages/invalid_package_vnf/Scripts/cloud_init/cloud-config.txt
@@ -19,7 +19,6 @@
 #

 

 #cloud-config

-password: osm4u

 chpasswd: { expire: False }

 ssh_pwauth: True

 

diff --git a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt
index f5d56f6..1e33dd4 100755
--- a/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt
+++ b/osm_common/tests/packages/native_charm_with_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt
@@ -20,7 +20,6 @@
 

 

 #cloud-config

-password: osm4u

 chpasswd: { expire: False }

 ssh_pwauth: True

 

diff --git a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt
index f5d56f6..1e33dd4 100755
--- a/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt
+++ b/osm_common/tests/packages/native_charm_without_metadata_dir_vnf/Scripts/cloud_init/cloud-config.txt
@@ -20,7 +20,6 @@
 

 

 #cloud-config

-password: osm4u

 chpasswd: { expire: False }

 ssh_pwauth: True

 

diff --git a/osm_common/tests/test_dbbase.py b/osm_common/tests/test_dbbase.py
index 050abdb..e582c7e 100644
--- a/osm_common/tests/test_dbbase.py
+++ b/osm_common/tests/test_dbbase.py
@@ -997,7 +997,6 @@
     def setUp(self, mock_logger):
         mock_logger = logging.getLogger()
         mock_logger.disabled = True
-        self.loop = asyncio.get_event_loop()
         self.encryption = Encryption(uri="uri", config={})
         self.encryption.encoding_type = encoding_type
         self.encryption.encrypt_mode = encyrpt_mode
@@ -1022,7 +1021,8 @@
             "ip": "192.168.12.23",
         }
         fields = ["secret", "cacert"]
-        self.loop.run_until_complete(
+
+        asyncio.run(
             self.encryption.decrypt_fields(input_item, fields, schema_version, salt)
         )
         self.assertEqual(input_item, expected_item)
@@ -1035,7 +1035,7 @@
         """item is empty and fields exists."""
         input_item = {}
         fields = ["secret", "cacert"]
-        self.loop.run_until_complete(
+        asyncio.run(
             self.encryption.decrypt_fields(input_item, fields, schema_version, salt)
         )
         self.assertEqual(input_item, {})
@@ -1046,7 +1046,7 @@
         """item exists and fields is empty."""
         input_item = copy.deepcopy(item)
         fields = []
-        self.loop.run_until_complete(
+        asyncio.run(
             self.encryption.decrypt_fields(input_item, fields, schema_version, salt)
         )
         self.assertEqual(input_item, item)
@@ -1064,7 +1064,7 @@
             "path": "/var",
             "ip": "192.168.12.23",
         }
-        self.loop.run_until_complete(
+        asyncio.run(
             self.encryption.decrypt_fields(input_item, fields, schema_version, salt)
         )
         self.assertEqual(input_item, expected_item)
@@ -1081,7 +1081,7 @@
         mock_decrypt.return_value = "mysecret"
         input_item = copy.deepcopy(item)
         fields = ["secret"]
-        self.loop.run_until_complete(
+        asyncio.run(
             self.encryption.decrypt_fields(input_item, fields, schema_version, salt)
         )
         self.assertEqual(input_item, item)
@@ -1097,7 +1097,7 @@
         fields = ["secret"]
         input_item = copy.deepcopy(item)
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(
+            asyncio.run(
                 self.encryption.decrypt_fields(input_item, fields, schema_version, salt)
             )
         self.assertEqual(
@@ -1113,9 +1113,7 @@
     def test_encrypt(self, mock_encrypt_value, mock_get_secret_key):
         """Method decrypt raises error."""
         mock_encrypt_value.return_value = encyrpted_value
-        result = self.loop.run_until_complete(
-            self.encryption.encrypt(value, schema_version, salt)
-        )
+        result = asyncio.run(self.encryption.encrypt(value, schema_version, salt))
         self.assertEqual(result, encyrpted_value)
         mock_get_secret_key.assert_called_once()
         mock_encrypt_value.assert_called_once_with(value, schema_version, salt)
@@ -1128,9 +1126,7 @@
         """Method get_secret_key raises error."""
         mock_get_secret_key.side_effect = DbException("Unexpected type.")
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(
-                self.encryption.encrypt(value, schema_version, salt)
-            )
+            asyncio.run(self.encryption.encrypt(value, schema_version, salt))
         self.assertEqual(str(error.exception), "database exception Unexpected type.")
         mock_get_secret_key.assert_called_once()
         mock_encrypt_value.assert_not_called()
@@ -1143,9 +1139,7 @@
             "A bytes-like object is required, not 'str'"
         )
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(
-                self.encryption.encrypt(value, schema_version, salt)
-            )
+            asyncio.run(self.encryption.encrypt(value, schema_version, salt))
         self.assertEqual(
             str(error.exception), "A bytes-like object is required, not 'str'"
         )
@@ -1157,7 +1151,7 @@
     def test_decrypt(self, mock_decrypt_value, mock_get_secret_key):
         """Decrypted successfully."""
         mock_decrypt_value.return_value = value
-        result = self.loop.run_until_complete(
+        result = asyncio.run(
             self.encryption.decrypt(encyrpted_value, schema_version, salt)
         )
         self.assertEqual(result, value)
@@ -1174,9 +1168,7 @@
         """Method get_secret_key raises error."""
         mock_get_secret_key.side_effect = DbException("Unexpected type.")
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(
-                self.encryption.decrypt(encyrpted_value, schema_version, salt)
-            )
+            asyncio.run(self.encryption.decrypt(encyrpted_value, schema_version, salt))
         self.assertEqual(str(error.exception), "database exception Unexpected type.")
         mock_get_secret_key.assert_called_once()
         mock_decrypt_value.assert_not_called()
@@ -1191,9 +1183,7 @@
             "A bytes-like object is required, not 'str'"
         )
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(
-                self.encryption.decrypt(encyrpted_value, schema_version, salt)
-            )
+            asyncio.run(self.encryption.decrypt(encyrpted_value, schema_version, salt))
         self.assertEqual(
             str(error.exception), "A bytes-like object is required, not 'str'"
         )
@@ -1281,7 +1271,7 @@
     def test_get_secret_key_exists(self, mock_join_keys):
         """secret_key exists."""
         self.encryption._secret_key = secret_key
-        self.loop.run_until_complete(self.encryption.get_secret_key())
+        asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(self.encryption.secret_key, secret_key)
         mock_join_keys.assert_not_called()
 
@@ -1295,7 +1285,7 @@
         self.encryption._admin_collection.find_one.return_value = None
         self.encryption._config = {"database_commonkey": "osm_new_key"}
         mock_join_keys.return_value = joined_key
-        self.loop.run_until_complete(self.encryption.get_secret_key())
+        asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(self.encryption.secret_key, joined_key)
         self.assertEqual(mock_join_keys.call_count, 1)
         mock_b64decode.assert_not_called()
@@ -1310,7 +1300,7 @@
         self.encryption._admin_collection.find_one.return_value = {"version": "1.0"}
         self.encryption._config = {"database_commonkey": "osm_new_key"}
         mock_join_keys.return_value = joined_key
-        self.loop.run_until_complete(self.encryption.get_secret_key())
+        asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(self.encryption.secret_key, joined_key)
         self.assertEqual(mock_join_keys.call_count, 1)
         mock_b64decode.assert_not_called()
@@ -1335,7 +1325,7 @@
         self.encryption._config = {"database_commonkey": "osm_new_key"}
         mock_join_keys.side_effect = [secret_key, joined_key]
         mock_b64decode.return_value = base64_decoded_serial
-        self.loop.run_until_complete(self.encryption.get_secret_key())
+        asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(self.encryption.secret_key, joined_key)
         self.assertEqual(mock_join_keys.call_count, 2)
         mock_b64decode.assert_called_once_with(serial_bytes)
@@ -1360,7 +1350,7 @@
         self.encryption._config = {"database_commonkey": "osm_new_key"}
         mock_join_keys.side_effect = DbException("Invalid data type.")
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(self.encryption.get_secret_key())
+            asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(str(error.exception), "database exception Invalid data type.")
         self.assertEqual(mock_join_keys.call_count, 1)
         check_if_assert_not_called(
@@ -1384,7 +1374,7 @@
             "A bytes-like object is required, not 'str'"
         )
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(self.encryption.get_secret_key())
+            asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(
             str(error.exception), "A bytes-like object is required, not 'str'"
         )
@@ -1410,7 +1400,7 @@
         self.encryption._config = {"database_commonkey": "osm_new_key"}
         mock_join_keys.return_value = secret_key
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(self.encryption.get_secret_key())
+            asyncio.run(self.encryption.get_secret_key())
         self.assertEqual(str(error.exception), "database exception Connection failed.")
         self.assertEqual(self.encryption.secret_key, None)
         self.assertEqual(mock_join_keys.call_count, 1)
@@ -1423,10 +1413,10 @@
 
     def test_encrypt_decrypt_with_schema_version_1_1_with_salt(self):
         """Encrypt and decrypt with schema version 1.1, salt exists."""
-        encrypted_msg = self.loop.run_until_complete(
+        encrypted_msg = asyncio.run(
             self.encryption.encrypt(value, schema_version, salt)
         )
-        decrypted_msg = self.loop.run_until_complete(
+        decrypted_msg = asyncio.run(
             self.encryption.decrypt(encrypted_msg, schema_version, salt)
         )
         self.assertEqual(value, decrypted_msg)
@@ -1434,10 +1424,10 @@
     def test_encrypt_decrypt_with_schema_version_1_0_with_salt(self):
         """Encrypt and decrypt with schema version 1.0, salt exists."""
         schema_version = "1.0"
-        encrypted_msg = self.loop.run_until_complete(
+        encrypted_msg = asyncio.run(
             self.encryption.encrypt(value, schema_version, salt)
         )
-        decrypted_msg = self.loop.run_until_complete(
+        decrypted_msg = asyncio.run(
             self.encryption.decrypt(encrypted_msg, schema_version, salt)
         )
         self.assertEqual(value, decrypted_msg)
@@ -1446,9 +1436,7 @@
         """Encrypt and decrypt with schema version 1.1, without salt."""
         salt = None
         with self.assertRaises(Exception) as error:
-            self.loop.run_until_complete(
-                self.encryption.encrypt(value, schema_version, salt)
-            )
+            asyncio.run(self.encryption.encrypt(value, schema_version, salt))
         self.assertEqual(str(error.exception), "'NoneType' object is not iterable")
 
 
diff --git a/osm_common/tests/test_msgbase.py b/osm_common/tests/test_msgbase.py
index d5092b1..41def48 100644
--- a/osm_common/tests/test_msgbase.py
+++ b/osm_common/tests/test_msgbase.py
@@ -16,7 +16,7 @@
 # For those usages not covered by the Apache License, Version 2.0 please
 # contact: esousa@whitestack.com or alfonso.tiernosepulveda@telefonica.com
 ##
-
+import asyncio
 import http
 
 from osm_common.msgbase import MsgBase, MsgException
@@ -64,20 +64,18 @@
     assert excinfo.value.http_code == http.HTTPStatus.INTERNAL_SERVER_ERROR
 
 
-def test_aiowrite(msg_base, event_loop):
+def test_aiowrite(msg_base):
     with pytest.raises(MsgException) as excinfo:
-        event_loop.run_until_complete(
-            msg_base.aiowrite("test", "test", "test", event_loop)
-        )
+        asyncio.run(msg_base.aiowrite("test", "test", "test"))
     assert str(excinfo.value).startswith(
         exception_message("Method 'aiowrite' not implemented")
     )
     assert excinfo.value.http_code == http.HTTPStatus.INTERNAL_SERVER_ERROR
 
 
-def test_aioread(msg_base, event_loop):
+def test_aioread(msg_base):
     with pytest.raises(MsgException) as excinfo:
-        event_loop.run_until_complete(msg_base.aioread("test", event_loop))
+        asyncio.run(msg_base.aioread("test"))
     assert str(excinfo.value).startswith(
         exception_message("Method 'aioread' not implemented")
     )
diff --git a/osm_common/tests/test_msglocal.py b/osm_common/tests/test_msglocal.py
index fb74586..b40b75c 100644
--- a/osm_common/tests/test_msglocal.py
+++ b/osm_common/tests/test_msglocal.py
@@ -16,7 +16,7 @@
 # For those usages not covered by the Apache License, Version 2.0 please
 # contact: esousa@whitestack.com or alfonso.tiernosepulveda@telefonica.com
 ##
-
+import asyncio
 import http
 import logging
 import os
@@ -437,7 +437,7 @@
         (["topic", "topic1", "topic2"], [{"key": "value"}, {"key1": "value1"}]),
     ],
 )
-def test_aioread(msg_local_with_data, event_loop, topics, datas):
+def test_aioread(msg_local_with_data, topics, datas):
     def write_to_topic(topics, datas):
         time.sleep(2)
         for topic in topics:
@@ -455,9 +455,7 @@
     t.start()
     for topic in topics:
         for data in datas:
-            recv = event_loop.run_until_complete(
-                msg_local_with_data.aioread(topic, event_loop)
-            )
+            recv = asyncio.run(msg_local_with_data.aioread(topic))
             recv_topic, recv_key, recv_msg = recv
             key = list(data.keys())[0]
             val = data[key]
@@ -467,22 +465,22 @@
     t.join()
 
 
-def test_aioread_exception(msg_local_with_data, event_loop):
+def test_aioread_exception(msg_local_with_data):
     msg_local_with_data.files_read = MagicMock()
     msg_local_with_data.files_read.__contains__.side_effect = Exception()
 
     with pytest.raises(MsgException) as excinfo:
-        event_loop.run_until_complete(msg_local_with_data.aioread("topic1", event_loop))
+        asyncio.run(msg_local_with_data.aioread("topic1"))
     assert str(excinfo.value).startswith(empty_exception_message())
     assert excinfo.value.http_code == http.HTTPStatus.INTERNAL_SERVER_ERROR
 
 
-def test_aioread_general_exception(msg_local_with_data, event_loop):
+def test_aioread_general_exception(msg_local_with_data):
     msg_local_with_data.read = MagicMock()
     msg_local_with_data.read.side_effect = Exception()
 
     with pytest.raises(MsgException) as excinfo:
-        event_loop.run_until_complete(msg_local_with_data.aioread("topic1", event_loop))
+        asyncio.run(msg_local_with_data.aioread("topic1"))
     assert str(excinfo.value).startswith(empty_exception_message())
     assert excinfo.value.http_code == http.HTTPStatus.INTERNAL_SERVER_ERROR
 
@@ -503,9 +501,9 @@
         ("test_topic", "test_none", None),
     ],
 )
-def test_aiowrite(msg_local_config, event_loop, topic, key, msg):
+def test_aiowrite(msg_local_config, topic, key, msg):
     file_path = msg_local_config.path + topic
-    event_loop.run_until_complete(msg_local_config.aiowrite(topic, key, msg))
+    asyncio.run(msg_local_config.aiowrite(topic, key, msg))
     assert os.path.exists(file_path)
 
     with open(file_path, "r") as stream:
@@ -530,12 +528,10 @@
         ("test_topic", "test_none", None, 3),
     ],
 )
-def test_aiowrite_with_multiple_calls(
-    msg_local_config, event_loop, topic, key, msg, times
-):
+def test_aiowrite_with_multiple_calls(msg_local_config, topic, key, msg, times):
     file_path = msg_local_config.path + topic
     for _ in range(times):
-        event_loop.run_until_complete(msg_local_config.aiowrite(topic, key, msg))
+        asyncio.run(msg_local_config.aiowrite(topic, key, msg))
     assert os.path.exists(file_path)
 
     with open(file_path, "r") as stream:
@@ -546,11 +542,11 @@
             }
 
 
-def test_aiowrite_exception(msg_local_config, event_loop):
+def test_aiowrite_exception(msg_local_config):
     msg_local_config.files_write = MagicMock()
     msg_local_config.files_write.__contains__.side_effect = Exception()
 
     with pytest.raises(MsgException) as excinfo:
-        event_loop.run_until_complete(msg_local_config.aiowrite("test", "test", "test"))
+        asyncio.run(msg_local_config.aiowrite("test", "test", "test"))
     assert str(excinfo.value).startswith(empty_exception_message())
     assert excinfo.value.http_code == http.HTTPStatus.INTERNAL_SERVER_ERROR