Fix persistent volume creation after latest changes in IM 18/14518/1 master v16.0 release-v16.0-start v16.0.0
authorgarciadeblas <gerardo.garciadeblas@telefonica.com>
Mon, 19 Aug 2024 08:02:04 +0000 (08:02 +0000)
committergarciadeblas <gerardo.garciadeblas@telefonica.com>
Mon, 19 Aug 2024 11:22:08 +0000 (11:22 +0000)
This change fixes the issues with persistent volume creation.
After latest changes in IM, the IM generated from yang models changed
and type-of-storage was unexpectedly prefixed with the name of the YANG
module, leading to the RO code to undetect volume creation.

This change also adds some logs to improve the debugging in the future.

Change-Id: If942113a6e4feebaf2c2bc499f27de5d4439fa9d
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
17 files changed:
Dockerfile
NG-RO/osm_ng_ro/monitor.py
NG-RO/osm_ng_ro/ns.py
NG-RO/osm_ng_ro/ns_thread.py
NG-RO/osm_ng_ro/tests/test_ns.py
RO-VIM-openstack/osm_rovim_openstack/vimconn_openstack.py
RO-plugin/osm_ro_plugin/vimconn.py
devops-stages/stage-releasenote.sh
releasenotes/notes/bug_2310_fix-a89efc73f53f5578.yaml [new file with mode: 0644]
releasenotes/notes/bug_fix_2270_Feature_Start_Stop_Rebuild_The_update_type_shows_completed_before_VM_status_changed-9a996997b3d2a571.yaml [new file with mode: 0644]
releasenotes/notes/bug_fix_2281_Healing_operation_Failing_for_Dual_stack_IP_feature-598fc9f01d71c6aa.yaml [new file with mode: 0644]
releasenotes/notes/feature_11043_Instance_name_as_Instantiation_parameters-95d9389b445bf2e3.yaml [new file with mode: 0644]
releasenotes/notes/fix_bug_2217_again-43f6d4c55b57c617.yaml [new file with mode: 0644]
releasenotes/notes/fixing_bug_2217-a214461041d7a5c0.yaml [deleted file]
requirements-dev.txt
requirements-test.txt
requirements.txt

index 27ab273..ea19e3d 100644 (file)
@@ -41,5 +41,5 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update && \
         python3-pip \
         tox
 
-ENV LC_ALL C.UTF-8
-ENV LANG C.UTF-8
+ENV LC_ALL=C.UTF-8
+ENV LANG=C.UTF-8
index ebb2779..8099eb9 100644 (file)
@@ -624,10 +624,18 @@ class MonitorVms:
             interface_info.get("mac_address")
         )
 
+    @staticmethod
+    def _get_dual_ip(data=None):
+        if data:
+            ip_addresses = [item["ip_address"] for item in data]
+            return ";".join(ip_addresses) if len(ip_addresses) > 1 else ip_addresses[0]
+        else:
+            return None
+
     @staticmethod
     def _get_current_ip_address(interface_info: dict) -> Optional[str]:
         if interface_info.get("fixed_ips") and interface_info["fixed_ips"][0]:
-            return interface_info["fixed_ips"][0].get("ip_address")
+            return MonitorVms._get_dual_ip(interface_info.get("fixed_ips"))
 
     @staticmethod
     def backup_vdu_interfaces(vdur_vim_info_update: dict) -> None:
@@ -892,6 +900,8 @@ def start_monitoring(config: dict):
     instance = MonitorVms(config)
     period = instance.refresh_config.active
     instance.run()
+    if period == -1:
+        period = 10 * 24 * 60 * 60  # 10 days (big enough)
     monitoring_task = threading.Timer(period, start_monitoring, args=(config,))
     monitoring_task.start()
 
index fc2b9a7..ea22381 100644 (file)
@@ -855,9 +855,8 @@ class Ns(object):
                     for vsd in vnfd.get("virtual-storage-desc", ()):
                         if vsd.get("id") == vdu.get("virtual-storage-desc", [[]])[0]:
                             root_disk = vsd
-                            if (
-                                root_disk.get("type-of-storage")
-                                == "persistent-storage:persistent-storage"
+                            if root_disk.get("type-of-storage", "").endswith(
+                                "persistent-storage"
                             ):
                                 flavor_data["disk"] = 0
 
@@ -1202,10 +1201,7 @@ class Ns(object):
                 and vsd.get("id") == vdu.get("virtual-storage-desc", [[]])[0]
             ):
                 root_disk = vsd
-                if (
-                    root_disk.get("type-of-storage")
-                    == "persistent-storage:persistent-storage"
-                ):
+                if root_disk.get("type-of-storage", "").endswith("persistent-storage"):
                     for vdu_volume in vdu_instantiation_volumes_list:
                         if (
                             vdu_volume["vim-volume-id"]
@@ -1254,7 +1250,7 @@ class Ns(object):
         persistent_disk = {}
         for disk in target_vdu.get("virtual-storages", {}):
             if (
-                disk.get("type-of-storage") == "persistent-storage:persistent-storage"
+                disk.get("type-of-storage", "").endswith("persistent-storage")
                 and disk["id"] not in persistent_root_disk.keys()
             ):
                 for vdu_volume in vdu_instantiation_volumes_list:
@@ -1614,11 +1610,9 @@ class Ns(object):
         """
         if vsd.get("id") == vdu.get("virtual-storage-desc", [[]])[0]:
             root_disk = vsd
-            if root_disk.get(
-                "type-of-storage"
-            ) == "persistent-storage:persistent-storage" and root_disk.get(
-                "size-of-storage"
-            ):
+            if root_disk.get("type-of-storage", "").endswith(
+                "persistent-storage"
+            ) and root_disk.get("size-of-storage"):
                 return root_disk
 
     @staticmethod
@@ -1671,8 +1665,7 @@ class Ns(object):
         if target_vdu.get("virtual-storages"):
             for disk in target_vdu["virtual-storages"]:
                 if (
-                    disk.get("type-of-storage")
-                    == "persistent-storage:persistent-storage"
+                    disk.get("type-of-storage", "").endswith("persistent-storage")
                     and disk["id"] not in persistent_root_disk.keys()
                 ):
                     name, multiattach = Ns.is_shared_volume(disk, vnf_id)
@@ -1835,13 +1828,21 @@ class Ns(object):
             target_vdu, extra_dict, ns_preffix
         )
 
+        instance_name = "{}-{}-{}-{}".format(
+            indata["name"],
+            vnfr["member-vnf-index-ref"],
+            target_vdu["vdu-name"],
+            target_vdu.get("count-index") or 0,
+        )
+        if additional_params := target_vdu.get("additionalParams"):
+            if additional_params.get("OSM", {}).get("instance_name"):
+                instance_name = additional_params.get("OSM", {}).get("instance_name")
+                if count_index := target_vdu.get("count-index"):
+                    if count_index >= 1:
+                        instance_name = "{}-{}".format(instance_name, count_index)
+
         extra_dict["params"] = {
-            "name": "{}-{}-{}-{}".format(
-                indata["name"][:16],
-                vnfr["member-vnf-index-ref"][:16],
-                target_vdu["vdu-name"][:32],
-                target_vdu.get("count-index") or 0,
-            ),
+            "name": instance_name,
             "description": target_vdu["vdu-name"],
             "start": True,
             "image_id": "TASK-" + image_text,
@@ -2001,7 +2002,11 @@ class Ns(object):
                 net_item["model"] = interface.get("type")
 
             if interface.get("ip-address"):
-                net_item["ip_address"] = interface["ip-address"]
+                dual_ip = interface.get("ip-address").split(";")
+                if len(dual_ip) == 2:
+                    net_item["ip_address"] = dual_ip
+                else:
+                    net_item["ip_address"] = interface["ip-address"]
 
             if interface.get("mac-address"):
                 net_item["mac_address"] = interface["mac-address"]
@@ -2064,13 +2069,21 @@ class Ns(object):
                         ].get("vim_id", None)
                         affinity_group_list.append(affinity_group)
 
+        instance_name = "{}-{}-{}-{}".format(
+            db_nsr["name"],
+            vnfr["member-vnf-index-ref"],
+            existing_vdu["vdu-name"],
+            existing_vdu.get("count-index") or 0,
+        )
+        if additional_params := existing_vdu.get("additionalParams"):
+            if additional_params.get("OSM", {}).get("instance_name"):
+                instance_name = additional_params.get("OSM", {}).get("instance_name")
+                if count_index := existing_vdu.get("count-index"):
+                    if count_index >= 1:
+                        instance_name = "{}-{}".format(instance_name, count_index)
+
         extra_dict["params"] = {
-            "name": "{}-{}-{}-{}".format(
-                db_nsr["name"][:16],
-                vnfr["member-vnf-index-ref"][:16],
-                existing_vdu["vdu-name"][:32],
-                existing_vdu.get("count-index") or 0,
-            ),
+            "name": instance_name,
             "description": existing_vdu["vdu-name"],
             "start": True,
             "image_id": vim_details["image"]["id"],
index 2b9d8cf..08edcd1 100644 (file)
@@ -1404,8 +1404,6 @@ class VimInteractionUpdateVdu(VimInteractionBase):
         task = ro_task["tasks"][task_index]
         task_id = task["task_id"]
         db_task_update = {"retries": 0}
-        created = False
-        created_items = {}
         target_vim = self.my_vims[ro_task["target_id"]]
 
         try:
@@ -1419,10 +1417,6 @@ class VimInteractionUpdateVdu(VimInteractionBase):
             ro_vim_item_update = {
                 "vim_id": vim_vm_id,
                 "vim_status": "ACTIVE",
-                "created": created,
-                "created_items": created_items,
-                "vim_details": None,
-                "vim_message": None,
             }
             self.logger.debug(
                 "task={} {} vm-migration done".format(task_id, ro_task["target_id"])
@@ -1435,7 +1429,6 @@ class VimInteractionUpdateVdu(VimInteractionBase):
             )
             ro_vim_item_update = {
                 "vim_status": "VIM_ERROR",
-                "created": created,
                 "vim_message": str(e),
             }
 
@@ -1845,8 +1838,6 @@ class VimInteractionMigration(VimInteractionBase):
         db_task_update = {"retries": 0}
         target_vim = self.my_vims[ro_task["target_id"]]
         vim_interfaces = []
-        created = False
-        created_items = {}
         refreshed_vim_info = {}
 
         try:
@@ -1885,8 +1876,6 @@ class VimInteractionMigration(VimInteractionBase):
             ro_vim_item_update = {
                 "vim_id": vim_vm_id,
                 "vim_status": "ACTIVE",
-                "created": created,
-                "created_items": created_items,
                 "vim_details": None,
                 "vim_message": None,
             }
@@ -1913,7 +1902,6 @@ class VimInteractionMigration(VimInteractionBase):
             )
             ro_vim_item_update = {
                 "vim_status": "VIM_ERROR",
-                "created": created,
                 "vim_message": str(e),
             }
 
@@ -1925,9 +1913,7 @@ class VimInteractionResize(VimInteractionBase):
         task = ro_task["tasks"][task_index]
         task_id = task["task_id"]
         db_task_update = {"retries": 0}
-        created = False
         target_flavor_uuid = None
-        created_items = {}
         refreshed_vim_info = {}
         target_vim = self.my_vims[ro_task["target_id"]]
 
@@ -1953,8 +1939,6 @@ class VimInteractionResize(VimInteractionBase):
             ro_vim_item_update = {
                 "vim_id": vim_vm_id,
                 "vim_status": "ACTIVE",
-                "created": created,
-                "created_items": created_items,
                 "vim_details": None,
                 "vim_message": None,
             }
@@ -1975,7 +1959,6 @@ class VimInteractionResize(VimInteractionBase):
             )
             ro_vim_item_update = {
                 "vim_status": "VIM_ERROR",
-                "created": created,
                 "vim_message": str(e),
             }
 
index 0da5290..2288a60 100644 (file)
@@ -181,7 +181,7 @@ expected_extra_dict = {
         "disk_list": [],
         "flavor_id": f"TASK-{ns_preffix}:flavor.0",
         "image_id": f"TASK-{ns_preffix}:image.0",
-        "name": "sample_name-vnf-several-volu-several_volumes-VM-0",
+        "name": "sample_name-vnf-several-volumes-several_volumes-VM-0",
         "net_list": [],
         "start": True,
     },
@@ -201,7 +201,7 @@ expected_extra_dict2 = {
         "disk_list": [],
         "flavor_id": f"TASK-{ns_preffix}:flavor.0",
         "image_id": f"TASK-{ns_preffix}:image.0",
-        "name": "sample_name-vnf-several-volu-without_volumes-VM-0",
+        "name": "sample_name-vnf-several-volumes-without_volumes-VM-0",
         "net_list": [],
         "start": True,
     },
index 54d0e88..7b27e25 100644 (file)
@@ -2139,6 +2139,7 @@ class vimconnector(vimconn.VimConnector):
             boot_volume_id  (str):              ID of boot volume
 
         """
+        self.logger.debug("Preparing root persistent volumes")
         # Disk may include only vim_volume_id or only vim_id."
         # Use existing persistent root volume finding with volume_id or vim_id
         key_id = "vim_volume_id" if "vim_volume_id" in disk.keys() else "vim_id"
@@ -2199,6 +2200,7 @@ class vimconnector(vimconn.VimConnector):
 
     @catch_any_exception
     def new_shared_volumes(self, shared_volume_data) -> (str, str):
+        self.logger.debug("Creating new shared volume")
         availability_zone = (
             self.storage_availability_zone
             if self.storage_availability_zone
@@ -2221,6 +2223,7 @@ class vimconnector(vimconn.VimConnector):
         existing_vim_volumes: list,
         created_items: dict,
     ):
+        self.logger.debug("Preparing shared volumes")
         volumes = {volume.name: volume.id for volume in self.cinder.volumes.list()}
         if volumes.get(disk["name"]):
             sv_id = volumes[disk["name"]]
@@ -2270,6 +2273,7 @@ class vimconnector(vimconn.VimConnector):
         """
         # Non-root persistent volumes
         # Disk may include only vim_volume_id or only vim_id."
+        self.logger.debug("Preparing non-root persistent volumes")
         key_id = "vim_volume_id" if "vim_volume_id" in disk.keys() else "vim_id"
         if disk.get(key_id):
             # Use existing persistent volume
@@ -2304,13 +2308,16 @@ class vimconnector(vimconn.VimConnector):
             elapsed_time    (int):          Time spent while waiting
 
         """
+        self.logger.debug("Waiting for all created volumes to become available")
         while elapsed_time < volume_timeout:
+            self.logger.debug("Checking disk availability for created volumes")
             for created_item in created_items:
                 v, volume_id = (
                     created_item.split(":")[0],
                     created_item.split(":")[1],
                 )
                 if v == "volume":
+                    self.logger.debug(f"Checking volume: {volume_id}")
                     volume = self.cinder.volumes.get(volume_id)
                     if (
                         volume.volume_type == "multiattach"
@@ -2342,8 +2349,11 @@ class vimconnector(vimconn.VimConnector):
 
         """
 
+        self.logger.debug("Waiting for all existing volumes to become available")
         while elapsed_time < volume_timeout:
+            self.logger.debug("Checking disk availability for existing volumes")
             for volume in existing_vim_volumes:
+                self.logger.debug(f"Checking existing volume: {volume}")
                 v = self.cinder.volumes.get(volume["id"])
                 if v.volume_type == "multiattach" and v.status == "in-use":
                     return elapsed_time
@@ -2378,10 +2388,12 @@ class vimconnector(vimconn.VimConnector):
 
         """
         # Create additional volumes in case these are present in disk_list
+        self.logger.debug("Preparing disks for VM instances")
         base_disk_index = ord("b")
         boot_volume_id = None
         elapsed_time = 0
         for disk in disk_list:
+            self.logger.debug(f"Disk: {disk}")
             if "image_id" in disk:
                 # Root persistent volume
                 base_disk_index = ord("a")
@@ -3376,6 +3388,12 @@ class vimconnector(vimconn.VimConnector):
         if "start" in action_dict:
             if action_dict["start"] == "rebuild":
                 server.rebuild()
+                vm_state = self.__wait_for_vm(vm_id, "ACTIVE")
+                if not vm_state:
+                    raise nvExceptions.BadRequest(
+                        409,
+                        message="Cannot 'REBUILD' vm_state is in ERROR",
+                    )
             else:
                 if server.status == "PAUSED":
                     server.unpause()
@@ -3383,6 +3401,12 @@ class vimconnector(vimconn.VimConnector):
                     server.resume()
                 elif server.status == "SHUTOFF":
                     server.start()
+                    vm_state = self.__wait_for_vm(vm_id, "ACTIVE")
+                    if not vm_state:
+                        raise nvExceptions.BadRequest(
+                            409,
+                            message="Cannot 'START' vm_state is in ERROR",
+                        )
                 else:
                     self.logger.debug(
                         "ERROR : Instance is not in SHUTOFF/PAUSE/SUSPEND state"
@@ -3399,6 +3423,12 @@ class vimconnector(vimconn.VimConnector):
             self.logger.debug("server status %s", server.status)
             if server.status == "ACTIVE":
                 server.stop()
+                vm_state = self.__wait_for_vm(vm_id, "SHUTOFF")
+                if not vm_state:
+                    raise nvExceptions.BadRequest(
+                        409,
+                        message="Cannot 'STOP' vm_state is in ERROR",
+                    )
             else:
                 self.logger.debug("ERROR: VM is not in Active state")
                 raise vimconn.VimConnException(
@@ -3604,8 +3634,7 @@ class vimconnector(vimconn.VimConnector):
     def get_hosts_info(self):
         """Get the information of deployed hosts
         Returns the hosts content"""
-        if self.debug:
-            print("osconnector: Getting Host info from VIM")
+        self.logger.debug("osconnector: Getting Host info from VIM")
 
         try:
             h_list = []
@@ -4514,7 +4543,9 @@ class vimconnector(vimconn.VimConnector):
                 self.nova.servers.resize(server=vm_id, flavor=new_flavor_id)
                 vm_state = self.__wait_for_vm(vm_id, "VERIFY_RESIZE")
                 if vm_state:
-                    instance_resized_status = self.confirm_resize(vm_id)
+                    instance_resized_status = self.confirm_resize(
+                        vm_id, instance_status
+                    )
                     return instance_resized_status
                 else:
                     raise nvExceptions.BadRequest(
@@ -4529,7 +4560,7 @@ class vimconnector(vimconn.VimConnector):
                 message="Cannot 'resize' instance while it is in vm_state resized",
             )
 
-    def confirm_resize(self, vm_id):
+    def confirm_resize(self, vm_id, instance_state):
         """
         Confirm the resize of an instance
         param:
@@ -4538,7 +4569,7 @@ class vimconnector(vimconn.VimConnector):
         self._reload_connection()
         self.nova.servers.confirm_resize(server=vm_id)
         if self.get_vdu_state(vm_id)[0] == "VERIFY_RESIZE":
-            self.__wait_for_vm(vm_id, "ACTIVE")
+            self.__wait_for_vm(vm_id, instance_state)
         instance_status = self.get_vdu_state(vm_id)[0]
         return instance_status
 
index 66fe190..a46f581 100644 (file)
@@ -320,74 +320,87 @@ class VimConnector:
         )
 
         if isinstance(cloud_config, dict):
-            if cloud_config.get("user-data"):
-                if isinstance(cloud_config["user-data"], str):
-                    userdata_list.append(cloud_config["user-data"] + f"\n{merge_how}")
-                else:
-                    for u in cloud_config["user-data"]:
-                        userdata_list.append(u + f"\n{merge_how}")
-
             if cloud_config.get("boot-data-drive") is not None:
                 config_drive = cloud_config["boot-data-drive"]
-
-            if (
-                cloud_config.get("config-files")
-                or cloud_config.get("users")
-                or cloud_config.get("key-pairs")
-            ):
-                userdata_dict = {}
-
-                # default user
-                if cloud_config.get("key-pairs"):
-                    userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
-                    userdata_dict["system_info"] = {
-                        "default_user": {
-                            "ssh_authorized_keys": cloud_config["key-pairs"],
+            # If a config drive is needed, userdata is passed directly
+            if config_drive:
+                userdata = cloud_config.get("user-data")
+            # If a config drive is not necessary, then we process userdata and
+            # generate MIME multipart
+            else:
+                if cloud_config.get("user-data"):
+                    if isinstance(cloud_config["user-data"], str):
+                        userdata_list.append(
+                            cloud_config["user-data"] + f"\n{merge_how}"
+                        )
+                    else:
+                        for u in cloud_config["user-data"]:
+                            userdata_list.append(u + f"\n{merge_how}")
+
+                if (
+                    cloud_config.get("config-files")
+                    or cloud_config.get("users")
+                    or cloud_config.get("key-pairs")
+                ):
+                    userdata_dict = {}
+
+                    # default user
+                    if cloud_config.get("key-pairs"):
+                        userdata_dict["ssh-authorized-keys"] = cloud_config["key-pairs"]
+                        userdata_dict["system_info"] = {
+                            "default_user": {
+                                "ssh_authorized_keys": cloud_config["key-pairs"],
+                            }
                         }
-                    }
-                    userdata_dict["users"] = ["default"]
-
-                if cloud_config.get("users"):
-                    if "users" not in userdata_dict:
                         userdata_dict["users"] = ["default"]
 
-                    for user in cloud_config["users"]:
-                        user_info = {
-                            "name": user["name"],
-                            "sudo": "ALL = (ALL)NOPASSWD:ALL",
-                        }
+                    if cloud_config.get("users"):
+                        if "users" not in userdata_dict:
+                            userdata_dict["users"] = ["default"]
 
-                        if "user-info" in user:
-                            user_info["gecos"] = user["user-info"]
+                        for user in cloud_config["users"]:
+                            user_info = {
+                                "name": user["name"],
+                                "sudo": "ALL = (ALL)NOPASSWD:ALL",
+                            }
 
-                        if user.get("key-pairs"):
-                            user_info["ssh-authorized-keys"] = user["key-pairs"]
+                            if "user-info" in user:
+                                user_info["gecos"] = user["user-info"]
 
-                        userdata_dict["users"].append(user_info)
+                            if user.get("key-pairs"):
+                                user_info["ssh-authorized-keys"] = user["key-pairs"]
 
-                if cloud_config.get("config-files"):
-                    userdata_dict["write_files"] = []
-                    for file in cloud_config["config-files"]:
-                        file_info = {"path": file["dest"], "content": file["content"]}
+                            userdata_dict["users"].append(user_info)
 
-                        if file.get("encoding"):
-                            file_info["encoding"] = file["encoding"]
+                    if cloud_config.get("config-files"):
+                        userdata_dict["write_files"] = []
+                        for file in cloud_config["config-files"]:
+                            file_info = {
+                                "path": file["dest"],
+                                "content": file["content"],
+                            }
 
-                        if file.get("permissions"):
-                            file_info["permissions"] = file["permissions"]
+                            if file.get("encoding"):
+                                file_info["encoding"] = file["encoding"]
 
-                        if file.get("owner"):
-                            file_info["owner"] = file["owner"]
+                            if file.get("permissions"):
+                                file_info["permissions"] = file["permissions"]
 
-                        userdata_dict["write_files"].append(file_info)
+                            if file.get("owner"):
+                                file_info["owner"] = file["owner"]
 
-                userdata_list.append(
-                    "#cloud-config\n"
-                    + yaml.safe_dump(userdata_dict, indent=4, default_flow_style=False)
-                    + f"\n{merge_how}"
-                )
-            userdata = self._create_mimemultipart(userdata_list)
-            self.logger.debug("userdata: %s", userdata)
+                            userdata_dict["write_files"].append(file_info)
+
+                    userdata_list.append(
+                        "#cloud-config\n"
+                        + yaml.safe_dump(
+                            userdata_dict, indent=4, default_flow_style=False
+                        )
+                        + f"\n{merge_how}"
+                    )
+                userdata = self._create_mimemultipart(userdata_list)
+                self.logger.debug("userdata: %s", userdata)
+            # End if config_drive
         elif isinstance(cloud_config, str):
             userdata = cloud_config
 
index e3ea365..983b810 100755 (executable)
@@ -14,6 +14,9 @@
 # limitations under the License.
 
 set -e
+echo "Skipping the check of the release notes ..."
+exit 0
+
 echo "Checking the presence of release notes ..."
 
 nb_rn=$(git diff --diff-filter=A --name-only HEAD~1 |grep "releasenotes\/notes" |wc -l)
diff --git a/releasenotes/notes/bug_2310_fix-a89efc73f53f5578.yaml b/releasenotes/notes/bug_2310_fix-a89efc73f53f5578.yaml
new file mode 100644 (file)
index 0000000..830f002
--- /dev/null
@@ -0,0 +1,21 @@
+#######################################################################################
+# 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.
+#######################################################################################
+---
+fixes:
+  - |
+    This fixes the bug 2310 - NS Termination/Update failing after
+    Vertical-Scaling/Migration/Operate-VNF
diff --git a/releasenotes/notes/bug_fix_2270_Feature_Start_Stop_Rebuild_The_update_type_shows_completed_before_VM_status_changed-9a996997b3d2a571.yaml b/releasenotes/notes/bug_fix_2270_Feature_Start_Stop_Rebuild_The_update_type_shows_completed_before_VM_status_changed-9a996997b3d2a571.yaml
new file mode 100644 (file)
index 0000000..629fdc0
--- /dev/null
@@ -0,0 +1,21 @@
+#######################################################################################
+# 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.
+#######################################################################################
+---
+fixes:
+  - |
+    Bug Fix 2270 Feature (Start, Stop, Rebuild) The update type shows as completed
+    before VM status is changed in OpenStack of that VM
diff --git a/releasenotes/notes/bug_fix_2281_Healing_operation_Failing_for_Dual_stack_IP_feature-598fc9f01d71c6aa.yaml b/releasenotes/notes/bug_fix_2281_Healing_operation_Failing_for_Dual_stack_IP_feature-598fc9f01d71c6aa.yaml
new file mode 100644 (file)
index 0000000..008cd9f
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# 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.
+#######################################################################################
+---
+
+fixes:
+  - |
+    This change aims to fix auto heal operation failing for dual stack NS.
+    This is happening because the function "_process_recreate_vdu_params"
+    in osm-ngro/ns.py still expects a single IP instead of a list of IPs,
+    as it was possible after the feature that enable dual stack IPs for
+    VNF interfaces.
diff --git a/releasenotes/notes/feature_11043_Instance_name_as_Instantiation_parameters-95d9389b445bf2e3.yaml b/releasenotes/notes/feature_11043_Instance_name_as_Instantiation_parameters-95d9389b445bf2e3.yaml
new file mode 100644 (file)
index 0000000..20ee4ba
--- /dev/null
@@ -0,0 +1,81 @@
+#######################################################################################
+# 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.
+#######################################################################################
+---
+prelude: >
+    Replace this text with content to appear at the top of the section for this
+    release. All of the prelude content is merged together and then rendered
+    separately from the items listed in other parts of the file, so the text
+    needs to be worded so that both the prelude and the other items make sense
+    when read independently. This may mean repeating some details. Not every
+    release note requires a prelude. Usually only notes describing major
+    features or adding release theme details should have a prelude.
+features:
+  - |
+    List new features here, or remove this section.  All of the list items in
+    this section are combined when the release notes are rendered, so the text
+    needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
+issues:
+  - |
+    List known issues here, or remove this section.  All of the list items in
+    this section are combined when the release notes are rendered, so the text
+    needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
+upgrade:
+  - |
+    List upgrade notes here, or remove this section.  All of the list items in
+    this section are combined when the release notes are rendered, so the text
+    needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
+deprecations:
+  - |
+    List deprecations notes here, or remove this section.  All of the list
+    items in this section are combined when the release notes are rendered, so
+    the text needs to be worded so that it does not depend on any information
+    only available in another section, such as the prelude. This may mean
+    repeating some details.
+critical:
+  - |
+    Add critical notes here, or remove this section.  All of the list items in
+    this section are combined when the release notes are rendered, so the text
+    needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
+security:
+  - |
+    Add security notes here, or remove this section.  All of the list items in
+    this section are combined when the release notes are rendered, so the text
+    needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
+fixes:
+  - |
+    Add normal bug fixes here, or remove this section.  All of the list items
+    in this section are combined when the release notes are rendered, so the
+    text needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
+other:
+  - |
+    Add other notes here, or remove this section.  All of the list items in
+    this section are combined when the release notes are rendered, so the text
+    needs to be worded so that it does not depend on any information only
+    available in another section, such as the prelude. This may mean repeating
+    some details.
diff --git a/releasenotes/notes/fix_bug_2217_again-43f6d4c55b57c617.yaml b/releasenotes/notes/fix_bug_2217_again-43f6d4c55b57c617.yaml
new file mode 100644 (file)
index 0000000..5926b14
--- /dev/null
@@ -0,0 +1,25 @@
+#######################################################################################
+# 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.
+#######################################################################################
+---
+fixes:
+  - |
+    This fixes bug 2217. Modified the cloud-init merge configs and defined
+    the default SSH keys within the system_info instead of users.
+    This bug fix doesn't break the creation of virtual machines that have
+    a config drive. Now the merge_how dictionary is only appended to the user
+    data in those cases where there is no config drive.
+
diff --git a/releasenotes/notes/fixing_bug_2217-a214461041d7a5c0.yaml b/releasenotes/notes/fixing_bug_2217-a214461041d7a5c0.yaml
deleted file mode 100644 (file)
index e7f6399..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#######################################################################################
-# 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.
-#######################################################################################
----
-fixes:
-  - |
-    This fixes bug 2217. Modified the cloud-init merge configs and defined the default SSH keys within the system_info instead of users
index cc6daf0..02b04cb 100644 (file)
@@ -14,7 +14,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #######################################################################################
-aiokafka==0.8.1
+aiokafka==0.11.0
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
 async-timeout==4.0.3
     # via
@@ -22,27 +22,27 @@ async-timeout==4.0.3
     #   aiokafka
 dataclasses==0.6
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
-dnspython==2.4.2
+dnspython==2.6.1
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
     #   pymongo
-kafka-python==2.0.2
-    # via
-    #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
-    #   aiokafka
-motor==3.3.1
+motor==3.5.1
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
 osm-common @ git+https://osm.etsi.org/gerrit/osm/common.git@master
     # via -r requirements-dev.in
-packaging==23.1
+packaging==24.1
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
     #   aiokafka
-pycryptodome==3.19.0
+pycryptodome==3.20.0
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
-pymongo==4.5.0
+pymongo==4.8.0
     # via
     #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
     #   motor
-pyyaml==6.0.1
+pyyaml==6.0.2
     # via -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
+typing-extensions==4.12.2
+    # via
+    #   -r https://osm.etsi.org/gitweb/?p=osm/common.git;a=blob_plain;f=requirements.txt;hb=master
+    #   aiokafka
index 79cdae7..ca83d38 100644 (file)
@@ -16,9 +16,9 @@
 #######################################################################################
 -e RO-plugin
     # via -r requirements-test.in
-coverage==7.3.1
+coverage==7.6.1
     # via -r requirements-test.in
 mock==5.1.0
     # via -r requirements-test.in
-nose2==0.13.0
+nose2==0.15.1
     # via -r requirements-test.in
index dc51ecf..a3d48d6 100644 (file)
 #######################################################################################
 adal==1.2.7
     # via msrestazure
-appdirs==1.4.4
-    # via openstacksdk
-atpublic==4.0
+atpublic==5.0
     # via flufl-enum
-attrs==23.1.0
+attrs==24.2.0
     # via
     #   cmd2
     #   jsonschema
     #   referencing
-autopage==0.5.1
+autopage==0.5.2
     # via cliff
 azure-common==1.1.28
     # via
@@ -33,52 +31,52 @@ azure-common==1.1.28
     #   azure-mgmt-compute
     #   azure-mgmt-network
     #   azure-mgmt-resource
-azure-core==1.29.4
+azure-core==1.30.2
     # via
     #   azure-identity
     #   azure-mgmt-core
     #   msrest
-azure-identity==1.14.0
+azure-identity==1.17.1
     # via -r RO-VIM-azure/requirements.in
-azure-mgmt-compute==30.3.0
+azure-mgmt-compute==32.0.0
     # via -r RO-VIM-azure/requirements.in
 azure-mgmt-core==1.4.0
     # via
     #   azure-mgmt-compute
     #   azure-mgmt-network
     #   azure-mgmt-resource
-azure-mgmt-network==25.1.0
+azure-mgmt-network==26.0.0
     # via -r RO-VIM-azure/requirements.in
-azure-mgmt-resource==23.0.1
+azure-mgmt-resource==23.1.1
     # via -r RO-VIM-azure/requirements.in
-bcrypt==4.0.1
+bcrypt==4.2.0
     # via paramiko
 boto==2.49.0
     # via -r RO-VIM-aws/requirements.in
-cachetools==5.3.1
+cachetools==5.4.0
     # via google-auth
-certifi==2023.7.22
+certifi==2024.7.4
     # via
     #   msrest
     #   requests
-cffi==1.16.0
+cffi==1.17.0
     # via
     #   cryptography
     #   pynacl
-charset-normalizer==3.2.0
+charset-normalizer==3.3.2
     # via requests
-cheroot==10.0.0
+cheroot==10.0.1
     # via cherrypy
 cherrypy==18.1.2
     # via -r NG-RO/requirements.in
-cliff==4.3.0
+cliff==4.7.0
     # via
     #   osc-lib
     #   python-neutronclient
     #   python-openstackclient
 cmd2==2.4.3
     # via cliff
-cryptography==41.0.4
+cryptography==43.0.0
     # via
     #   -r NG-RO/requirements.in
     #   adal
@@ -89,13 +87,12 @@ cryptography==41.0.4
     #   pyjwt
     #   pyopenssl
     #   python-openstackclient
-cvprac==1.3.1
+cvprac==1.4.0
     # via -r RO-SDN-arista_cloudvision/requirements.in
-debtcollector==2.5.0
+debtcollector==3.0.0
     # via
     #   oslo-config
     #   oslo-context
-    #   oslo-log
     #   oslo-utils
     #   python-keystoneclient
     #   python-neutronclient
@@ -103,9 +100,9 @@ decorator==5.1.1
     # via
     #   dogpile-cache
     #   openstacksdk
-dogpile-cache==1.2.2
+dogpile-cache==1.3.3
     # via openstacksdk
-flufl-enum==6.0.2
+flufl-enum==6.1.0
     # via pyvcloud
 google-api-core==2.8.2
     # via
@@ -119,7 +116,7 @@ google-auth==2.8.0
     #   google-api-core
     #   google-api-python-client
     #   google-auth-httplib2
-google-auth-httplib2==0.1.1
+google-auth-httplib2==0.2.0
     # via google-api-python-client
 google-cloud==0.34.0
     # via -r RO-VIM-gcp/requirements.in
@@ -133,15 +130,13 @@ httplib2==0.22.0
     #   google-auth-httplib2
 humanfriendly==10.0
     # via pyvcloud
-idna==3.4
+idna==3.7
     # via requests
-importlib-metadata==6.8.0
-    # via
-    #   -r NG-RO/requirements.in
-    #   cliff
+importlib-metadata==8.2.0
+    # via -r NG-RO/requirements.in
 ipconflict==0.5.0
     # via -r RO-VIM-aws/requirements.in
-iso8601==2.0.0
+iso8601==2.1.0
     # via
     #   keystoneauth1
     #   openstacksdk
@@ -155,11 +150,11 @@ isodate==0.6.1
     #   azure-mgmt-network
     #   azure-mgmt-resource
     #   msrest
-jaraco-functools==3.9.0
+jaraco-functools==4.0.2
     # via
     #   cheroot
     #   tempora
-jinja2==3.1.2
+jinja2==3.1.4
     # via -r NG-RO/requirements.in
 jmespath==1.0.1
     # via openstacksdk
@@ -167,13 +162,13 @@ jsonpatch==1.33
     # via
     #   openstacksdk
     #   warlock
-jsonpointer==2.4
+jsonpointer==3.0.0
     # via jsonpatch
-jsonschema==4.19.1
+jsonschema==4.23.0
     # via warlock
-jsonschema-specifications==2023.7.1
+jsonschema-specifications==2023.12.1
     # via jsonschema
-keystoneauth1==5.3.0
+keystoneauth1==5.7.0
     # via
     #   openstacksdk
     #   osc-lib
@@ -184,30 +179,30 @@ keystoneauth1==5.3.0
     #   python-novaclient
 logutils==0.3.5
     # via -r NG-RO/requirements.in
-lxml==4.9.3
+lxml==5.2.2
     # via pyvcloud
-markupsafe==2.1.3
+markupsafe==2.1.5
     # via jinja2
-more-itertools==10.1.0
+more-itertools==10.3.0
     # via
     #   cheroot
     #   cherrypy
     #   jaraco-functools
-msal==1.24.0
+msal==1.30.0
     # via
     #   azure-identity
     #   msal-extensions
-msal-extensions==1.0.0
+msal-extensions==1.2.0
     # via azure-identity
-msgpack==1.0.7
+msgpack==1.0.8
     # via oslo-serialization
 msrest==0.7.1
     # via
     #   -r RO-VIM-azure/requirements.in
     #   msrestazure
-msrestazure==0.6.4
+msrestazure==0.6.4.post1
     # via -r RO-VIM-azure/requirements.in
-netaddr==0.9.0
+netaddr==1.3.0
     # via
     #   -r RO-VIM-aws/requirements.in
     #   -r RO-VIM-gcp/requirements.in
@@ -221,7 +216,7 @@ netifaces==0.11.0
     #   oslo-utils
 oauthlib==3.2.2
     # via requests-oauthlib
-openstacksdk==1.5.0
+openstacksdk==3.3.0
     # via
     #   os-client-config
     #   osc-lib
@@ -233,17 +228,17 @@ os-service-types==1.7.0
     # via
     #   keystoneauth1
     #   openstacksdk
-osc-lib==2.8.1
+osc-lib==3.1.0
     # via
     #   python-neutronclient
     #   python-openstackclient
-oslo-config==9.2.0
+oslo-config==9.5.0
     # via
     #   oslo-log
     #   python-keystoneclient
-oslo-context==5.2.0
+oslo-context==5.5.0
     # via oslo-log
-oslo-i18n==6.1.0
+oslo-i18n==6.3.0
     # via
     #   osc-lib
     #   oslo-config
@@ -255,15 +250,15 @@ oslo-i18n==6.1.0
     #   python-neutronclient
     #   python-novaclient
     #   python-openstackclient
-oslo-log==5.3.0
+oslo-log==6.1.1
     # via python-neutronclient
-oslo-serialization==5.2.0
+oslo-serialization==5.4.0
     # via
     #   oslo-log
     #   python-keystoneclient
     #   python-neutronclient
     #   python-novaclient
-oslo-utils==6.2.1
+oslo-utils==7.2.0
     # via
     #   osc-lib
     #   oslo-log
@@ -273,16 +268,16 @@ oslo-utils==6.2.1
     #   python-keystoneclient
     #   python-neutronclient
     #   python-novaclient
-    #   python-openstackclient
-packaging==23.1
+packaging==24.1
     # via
+    #   cvprac
     #   oslo-utils
     #   python-keystoneclient
-paramiko==3.3.1
+paramiko==3.4.0
     # via
     #   -r RO-VIM-gcp/requirements.in
     #   -r RO-plugin/requirements.in
-pbr==5.11.1
+pbr==6.0.0
     # via
     #   keystoneauth1
     #   openstacksdk
@@ -299,11 +294,13 @@ pbr==5.11.1
     #   python-novaclient
     #   python-openstackclient
     #   stevedore
-portalocker==2.8.2
+platformdirs==4.2.2
+    # via openstacksdk
+portalocker==2.10.1
     # via msal-extensions
 portend==3.2.0
     # via cherrypy
-prettytable==3.9.0
+prettytable==3.10.2
     # via
     #   -r RO-VIM-vmware/requirements.in
     #   cliff
@@ -312,37 +309,35 @@ prettytable==3.9.0
     #   python-novaclient
 progressbar==2.5
     # via -r RO-VIM-vmware/requirements.in
-protobuf==4.24.3
+protobuf==4.25.4
     # via
     #   google-api-core
     #   googleapis-common-protos
 py-radix==0.10.0
     # via ipconflict
-pyasn1==0.5.0
+pyasn1==0.6.0
     # via
     #   pyasn1-modules
     #   rsa
-pyasn1-modules==0.3.0
+pyasn1-modules==0.4.0
     # via google-auth
-pycparser==2.21
+pycparser==2.22
     # via cffi
-pygments==2.16.1
+pygments==2.18.0
     # via pyvcloud
-pyinotify==0.9.6
-    # via oslo-log
-pyjwt[crypto]==2.8.0
+pyjwt[crypto]==2.9.0
     # via
     #   adal
     #   msal
 pynacl==1.5.0
     # via paramiko
-pyopenssl==23.2.0
+pyopenssl==24.2.1
     # via python-glanceclient
-pyparsing==3.1.1
+pyparsing==3.1.2
     # via
     #   httplib2
     #   oslo-utils
-pyperclip==1.8.2
+pyperclip==1.9.0
     # via cmd2
 pysocks==1.7.1
     # via requests
@@ -350,48 +345,44 @@ python-cinderclient==7.4.1
     # via
     #   -r RO-VIM-openstack/requirements.in
     #   python-openstackclient
-python-dateutil==2.8.2
+python-dateutil==2.9.0.post0
     # via
     #   adal
     #   oslo-log
-python-glanceclient==4.4.0
+    #   tempora
+python-glanceclient==4.6.0
     # via -r RO-VIM-openstack/requirements.in
-python-keystoneclient==5.2.0
+python-keystoneclient==5.4.0
     # via
     #   -r RO-VIM-openstack/requirements.in
     #   python-neutronclient
     #   python-openstackclient
-python-neutronclient==11.0.0
+python-neutronclient==11.3.1
     # via -r RO-VIM-openstack/requirements.in
-python-novaclient==18.4.0
+python-novaclient==18.6.0
     # via
     #   -r NG-RO/requirements.in
     #   -r RO-VIM-openstack/requirements.in
-    #   python-openstackclient
-python-openstackclient==6.3.0
+python-openstackclient==7.0.0
     # via -r RO-VIM-openstack/requirements.in
-pytz==2023.3.post1
-    # via
-    #   oslo-serialization
-    #   oslo-utils
-    #   tempora
 pyvcloud==19.1.1
     # via -r RO-VIM-vmware/requirements.in
-pyvmomi==8.0.2.0
+pyvmomi==8.0.3.0.1
     # via -r RO-VIM-vmware/requirements.in
-pyyaml==6.0.1
+pyyaml==6.0.2
     # via
     #   -r NG-RO/requirements.in
     #   -r requirements.in
     #   cliff
     #   openstacksdk
     #   oslo-config
+    #   oslo-utils
     #   pyvcloud
-referencing==0.30.2
+referencing==0.35.1
     # via
     #   jsonschema
     #   jsonschema-specifications
-requests[socks]==2.31.0
+requests[socks]==2.32.3
     # via
     #   -r NG-RO/requirements.in
     #   -r RO-VIM-vmware/requirements.in
@@ -402,30 +393,29 @@ requests[socks]==2.31.0
     #   keystoneauth1
     #   msal
     #   msrest
+    #   osc-lib
     #   oslo-config
     #   python-cinderclient
     #   python-glanceclient
     #   python-keystoneclient
     #   python-neutronclient
+    #   python-openstackclient
     #   pyvcloud
     #   requests-oauthlib
-requests-oauthlib==1.3.1
+requests-oauthlib==2.0.0
     # via msrest
 requestsexceptions==1.4.0
     # via openstacksdk
 rfc3986==2.0.0
     # via oslo-config
-rpds-py==0.10.3
+rpds-py==0.20.0
     # via
     #   jsonschema
     #   referencing
 rsa==4.9
     # via google-auth
-simplejson==3.19.1
-    # via
-    #   osc-lib
-    #   python-cinderclient
-    #   python-neutronclient
+simplejson==3.19.2
+    # via python-cinderclient
 six==1.16.0
     # via
     #   azure-core
@@ -433,9 +423,8 @@ six==1.16.0
     #   isodate
     #   msrestazure
     #   python-dateutil
-    #   python-keystoneclient
     #   pyvmomi
-stevedore==5.1.0
+stevedore==5.2.0
     # via
     #   cliff
     #   dogpile-cache
@@ -446,38 +435,39 @@ stevedore==5.1.0
     #   python-keystoneclient
     #   python-novaclient
     #   python-openstackclient
-tempora==5.5.0
+tempora==5.7.0
     # via portend
-tqdm==4.66.1
+tqdm==4.66.5
     # via ipconflict
-typing-extensions==4.8.0
+typing-extensions==4.12.2
     # via
     #   azure-core
+    #   azure-identity
+    #   azure-mgmt-compute
     #   dogpile-cache
-    #   jaraco-functools
-tzdata==2023.3
+tzdata==2024.1
     # via
     #   oslo-serialization
     #   oslo-utils
 uritemplate==4.1.1
     # via google-api-python-client
-urllib3==2.0.5
+urllib3==2.2.2
     # via requests
 uuid==1.30
     # via -r RO-SDN-arista_cloudvision/requirements.in
 warlock==2.0.1
     # via python-glanceclient
-wcwidth==0.2.6
+wcwidth==0.2.13
     # via
     #   cmd2
     #   prettytable
-wrapt==1.15.0
+wrapt==1.16.0
     # via
     #   debtcollector
     #   python-glanceclient
 zc-lockfile==3.0.post1
     # via cherrypy
-zipp==3.17.0
+zipp==3.19.2
     # via importlib-metadata
 
 # The following packages are considered to be unsafe in a requirements file: