Update from master part 2
Squashed commit of the following:
commit 364627c364a86a85696781766326dd690a362bc4
Author: vegall <lvega@whitestack.com>
Date: Fri Mar 17 15:09:50 2023 +0000
Feature 10972: Support of volume multi-attach
Change-Id: I6e88ee52e5e882dbb4ec7d66cf648fbe07d40509
Signed-off-by: vegall <lvega@whitestack.com>
commit 0e51779fd37dc5c12f3bd19d78f7341ed0a67b7a
Author: gifrerenom <lluis.gifre@cttc.es>
Date: Tue Apr 18 16:38:42 2023 +0000
Feature 10937: Transport API (TAPI) WIM connector for RO
Change-Id: If0dac9f8ba2d00945eb86a89fb0b2f174c672794
Signed-off-by: gifrerenom <lluis.gifre@cttc.es>
commit 370e36bafdcb90f212e289b87290f39be141b3d4
Author: elumalai <deepika.e@tataelxsi.co.in>
Date: Tue Apr 25 16:22:56 2023 +0530
Feature 10979: Static IPv6 Dual Stack Assignment
Added support for static dual stack IP assignment
Change-Id: Ief10ae955fb870a3417f68e1c5f7bda570cb6470
Signed-off-by: elumalai <deepika.e@tataelxsi.co.in>
commit b1bc66933aa392b9d7518f7cebc711700335389c
Author: Gabriel Cuba <gcuba@whitestack.com>
Date: Fri Aug 19 18:23:00 2022 -0500
Fix Bug 2098: Get VDUs from VNFR when Heal op has no additionalPrameters
When Heal is requested without vdu or count-index parameters, RO will recreate all VDUs from VNFR
Change-Id: Idf2cf158bcb33e7b0c307298c14504cc7aa77e2a
Signed-off-by: Gabriel Cuba <gcuba@whitestack.com>
(cherry picked from commit 2fbb3a264e4117f4a6569fede6558836d67ac4a4)
commit aba1518f487b4b65861eb30f553c4edb72ad972e
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date: Mon May 15 11:55:13 2023 +0300
Fix VimAdminThread run method
The run_coroutine_threadsafe() function is used to schedule a coroutine object from a different thread and returns a concurrent.futures.Future.
run_coroutine_threadsafe is unnecessary to run the main task and replaced with asyncio.run().
Change-Id: I8ea31828a9798140d596165443bdf26659b4eef8
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
commit f17e5bb6b6da4432628dd65ce9ad633e6441f67c
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date: Wed May 10 22:52:57 2023 +0300
Minor updates in Dockerfile
Change-Id: I79b43654d181f6976a4e544d58fb92aa1b67e760
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
commit a264b7a460b28d7454fc95fe659da46f55b0c155
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date: Tue May 9 14:57:22 2023 +0300
Ubuntu 22.04 and Python 3.10 preparation
Change-Id: I87164827a8849c16b5e3a804d9673a578e5a5593
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
commit 1c89c08a0dd1c79b5adff3ac1cc123239762e06a
Author: garciadeblas <gerardo.garciadeblas@telefonica.com>
Date: Tue Apr 18 15:06:30 2023 +0200
Clean stage-archive.sh and use allowlist_extenals in tox.ini
Change-Id: I18f0bc3e263063b5b1d2cf211f028f6bb0e4bceb
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
commit 51e72a0f7479b3064b4b11891eb524d42f4738b0
Author: elumalai <deepika.e@tataelxsi.co.in>
Date: Fri Apr 28 19:41:49 2023 +0530
Coverity CWE 330: Use of Insufficiently Random Values
Added support to fix CWE 330: Use of Insufficiently Random Values
Coverity issue
Change-Id: Ib12ebeeb9b0cc10af9980fe8661eb6230c2f6d6d
Signed-off-by: elumalai <deepika.e@tataelxsi.co.in>
commit e17cd946aed699b5feca83d37591d04f129a8f52
Author: elumalai <deepika.e@tataelxsi.co.in>
Date: Fri Apr 28 18:04:24 2023 +0530
Coverity CWE 688: Function Call With Incorrect Variable or Reference as Argument
Added fix for CWE 688 Typo in Identifier
Change-Id: I53b5142451b809be638d73626265531057722169
Signed-off-by: elumalai <deepika.e@tataelxsi.co.in>
commit 730cfaff466fb3c9b1446ecef5213916195ff861
Author: Gabriel Cuba <gcuba@whitestack.com>
Date: Mon Mar 13 22:26:38 2023 -0500
Feature 10975: get flavor-id from additionalParams if specified
Change-Id: I1c9b1ec43c80f3793b475187681f4c2005d77375
Signed-off-by: Gabriel Cuba <gcuba@whitestack.com>
commit 2d3f63b055e6a38e95bcff56a8ddef32767b11ef
Author: garciadeblas <gerardo.garciadeblas@telefonica.com>
Date: Tue Apr 11 10:08:26 2023 +0200
Update stage-build to run tox sequentially
Change-Id: I967f19a8c35700290e93c9d8bd863b63b7c2d239
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
(cherry picked from commit ea063c7a6ae6a5d7e11e8c22f9707d5c8f674ac7)
commit b3dbfcad6f4b2bebc9ebc20fd7129a18879cb20c
Author: Gabriel Cuba <gcuba@whitestack.com>
Date: Tue Mar 14 10:58:39 2023 -0500
Feature 10978: Add support of ipv6_address_mode and ipv6_ra_mode to openstack connector
Change-Id: I8ca741a215bd2c52999dee1ea301d4e02aafcb24
Signed-off-by: Gabriel Cuba <gcuba@whitestack.com>
commit 01619d5b596e01ac8cd6d27bf01a1174e6b3f97b
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date: Wed Mar 22 22:57:26 2023 +0300
Keep vim_details while reporting VM deletion
Change-Id: I27577b2fc93a585affc947abcec8352562f23f49
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
commit 98740c03567ff8c5a22f06fd3f049248a9e5f98d
Author: Pedro Escaleira <escaleira@av.it.pt>
Date: Wed Feb 22 10:48:52 2023 +0000
Bug 2217 fixed: modified the cloud-init merge configs and defined the default SSH keys within the system_info instead of users
Change-Id: I12e26a88fb9b50c4a78b9fa8ee2cb5d4b4bf6d00
Signed-off-by: Pedro Escaleira <escaleira@av.it.pt>
commit d586d89bde00acaf22debd7f657d605c9d095571
Author: Gulsum Atici <gulsum.atici@canonical.com>
Date: Mon Feb 13 18:40:03 2023 +0300
Feature 10960 Performance optimizations for the polling of VM status in RO
Change-Id: If785bbeaab66e0839541bf94184ce37114e67bd4
Signed-off-by: Gulsum Atici <gulsum.atici@canonical.com>
commit 4c1dd54ae02e82f11a60058a1b7c7b0137ac572e
Author: Gabriel Cuba <gcuba@whitestack.com>
Date: Tue Feb 14 12:43:32 2023 -0500
Refactor ns.py so that RO uses the IP profile as it comes from LCM
Change-Id: I36983c86d7c76ad8a9b93eb6eae254f844717e0e
Signed-off-by: Gabriel Cuba <gcuba@whitestack.com>
commit 3822010a26b2e21290b6acdf288db277c7f36605
Author: garciadeblas <gerardo.garciadeblas@telefonica.com>
Date: Mon Feb 13 17:48:32 2023 +0100
Fix bug 2216 to remove hardcoded numa affinity in VIO
Change-Id: I0912c2841e7c5c1febe056ba092afedaea77f6a1
Signed-off-by: garciadeblas <gerardo.garciadeblas@telefonica.com>
commit 778f3cc8c052bd17d0da32f07b880616d25f935a
Author: Lovejeet Singh <lovejeet.singh@hsc.com>
Date: Mon Feb 13 16:15:40 2023 +0530
Bug 2202: Adding support for cinder V3 API with V2 API for persistent volumes.
Change-Id: I7034564b91b94e6be242cb2ce0f4a5b147b87d64
Signed-off-by: Lovejeet Singh <lovejeet.singh@hsc.com>
Change-Id: I7ac1bd1d9896788812f456c678b1f5222a1f1ad6
Signed-off-by: Dario Faccin <dario.faccin@canonical.com>
diff --git a/RO-SDN-tapi/osm_rosdn_tapi/wimconn_tapi.py b/RO-SDN-tapi/osm_rosdn_tapi/wimconn_tapi.py
new file mode 100644
index 0000000..a89f4c8
--- /dev/null
+++ b/RO-SDN-tapi/osm_rosdn_tapi/wimconn_tapi.py
@@ -0,0 +1,346 @@
+# -*- coding: utf-8 -*-
+
+#######################################################################################
+# This file is part of OSM RO module
+#
+# 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.
+#######################################################################################
+# This work has been performed in the context of the TeraFlow Project -
+# funded by the European Commission under Grant number 101015857 through the
+# Horizon 2020 program.
+# Contributors:
+# - Lluis Gifre <lluis.gifre@cttc.es>
+# - Ricard Vilalta <ricard.vilalta@cttc.es>
+#######################################################################################
+
+"""The SDN/WIM connector is responsible for establishing wide area network
+connectivity.
+
+This SDN/WIM connector implements the standard ONF Transport API (TAPI).
+
+It receives the endpoints and the necessary details to request the Layer 2
+service through the use of the ONF Transport API.
+"""
+
+import logging
+import uuid
+
+from osm_ro_plugin.sdnconn import SdnConnectorBase
+
+from .conn_info import (
+ conn_info_compose_bidirectional,
+ conn_info_compose_unidirectional,
+)
+from .exceptions import (
+ WimTapiConnectionPointsBadFormat,
+ WimTapiMissingConnPointField,
+ WimTapiUnsupportedServiceType,
+)
+from .services_composer import ServicesComposer
+from .tapi_client import TransportApiClient
+
+
+class WimconnectorTAPI(SdnConnectorBase):
+ """ONF TAPI WIM connector"""
+
+ def __init__(self, wim, wim_account, config=None, logger=None):
+ """ONF TAPI WIM connector
+
+ Arguments:
+ wim (dict): WIM record, as stored in the database
+ wim_account (dict): WIM account record, as stored in the database
+ config (optional dict): optional configuration from the configuration database
+ logger (optional Logger): logger to use with this WIM connector
+ The arguments of the constructor are converted to object attributes.
+ An extra property, ``service_endpoint_mapping`` is created from ``config``.
+ """
+ logger = logger or logging.getLogger("ro.sdn.tapi")
+
+ super().__init__(wim, wim_account, config, logger)
+
+ self.logger.debug("self.config={:s}".format(str(self.config)))
+
+ if len(self.service_endpoint_mapping) == 0 and self.config.get(
+ "wim_port_mapping"
+ ):
+ self.service_endpoint_mapping = self.config.get("wim_port_mapping", [])
+
+ self.mappings = {
+ m["service_endpoint_id"]: m for m in self.service_endpoint_mapping
+ }
+
+ self.logger.debug("self.mappings={:s}".format(str(self.mappings)))
+
+ self.tapi_client = TransportApiClient(self.logger, wim, wim_account, config)
+
+ self.logger.info("TAPI WIM Connector Initialized.")
+
+ def check_credentials(self):
+ """Check if the connector itself can access the SDN/WIM with the provided url (wim.wim_url),
+ user (wim_account.user), and password (wim_account.password)
+
+ Raises:
+ SdnConnectorError: Issues regarding authorization, access to
+ external URLs, etc are detected.
+ """
+ _ = self.tapi_client.get_root_context()
+ self.logger.info("Credentials checked")
+
+ def get_connectivity_service_status(self, service_uuid, conn_info=None):
+ """Monitor the status of the connectivity service established
+
+ Arguments:
+ service_uuid (str): UUID of the connectivity service
+ conn_info (dict or None): Information returned by the connector
+ during the service creation/edition and subsequently stored in
+ the database.
+
+ Returns:
+ dict: JSON/YAML-serializable dict that contains a mandatory key
+ ``sdn_status`` associated with one of the following values::
+
+ {'sdn_status': 'ACTIVE'}
+ # The service is up and running.
+
+ {'sdn_status': 'INACTIVE'}
+ # The service was created, but the connector
+ # cannot determine yet if connectivity exists
+ # (ideally, the caller needs to wait and check again).
+
+ {'sdn_status': 'DOWN'}
+ # Connection was previously established,
+ # but an error/failure was detected.
+
+ {'sdn_status': 'ERROR'}
+ # An error occurred when trying to create the service/
+ # establish the connectivity.
+
+ {'sdn_status': 'BUILD'}
+ # Still trying to create the service, the caller
+ # needs to wait and check again.
+
+ Additionally ``error_msg``(**str**) and ``sdn_info``(**dict**)
+ keys can be used to provide additional status explanation or
+ new information available for the connectivity service.
+ """
+ sdn_status = set()
+ bidirectional = conn_info["bidirectional"]
+
+ tapi_client = self.tapi_client
+ if bidirectional:
+ service_uuid = conn_info["uuid"]
+ service_status = tapi_client.get_service_status("<>", service_uuid)
+ sdn_status.add(service_status["sdn_status"])
+ else:
+ service_az_uuid = conn_info["az"]["uuid"]
+ service_za_uuid = conn_info["za"]["uuid"]
+ service_az_status = tapi_client.get_service_status(">>", service_az_uuid)
+ service_za_status = tapi_client.get_service_status("<<", service_za_uuid)
+ sdn_status.add(service_az_status["sdn_status"])
+ sdn_status.add(service_za_status["sdn_status"])
+
+ if len(sdn_status) == 1 and "ACTIVE" in sdn_status:
+ service_status = {"sdn_status": "ACTIVE"}
+ else:
+ service_status = {"sdn_status": "ERROR"}
+
+ return service_status
+
+ def create_connectivity_service(self, service_type, connection_points, **kwargs):
+ """
+ Establish SDN/WAN connectivity between the endpoints
+ :param service_type: (str): ``ELINE`` (L2), ``ELAN`` (L2), ``ETREE`` (L2), ``L3``.
+ :param connection_points: (list): each point corresponds to
+ an entry point to be connected. For WIM: from the DC to the transport network.
+ For SDN: Compute/PCI to the transport network. One
+ connection point serves to identify the specific access and
+ some other service parameters, such as encapsulation type.
+ Each item of the list is a dict with:
+ "service_endpoint_id": (str)(uuid) Same meaning that for 'service_endpoint_mapping' (see __init__)
+ In case the config attribute mapping_not_needed is True, this value is not relevant. In this case
+ it will contain the string "device_id:device_interface_id"
+ "service_endpoint_encapsulation_type": None, "dot1q", ...
+ "service_endpoint_encapsulation_info": (dict) with:
+ "vlan": ..., (int, present if encapsulation is dot1q)
+ "vni": ... (int, present if encapsulation is vxlan),
+ "peers": [(ipv4_1), (ipv4_2)] (present if encapsulation is vxlan)
+ "mac": ...
+ "device_id": ..., same meaning that for 'service_endpoint_mapping' (see __init__)
+ "device_interface_id": same meaning that for 'service_endpoint_mapping' (see __init__)
+ "switch_dpid": ..., present if mapping has been found for this device_id,device_interface_id
+ "swith_port": ... present if mapping has been found for this device_id,device_interface_id
+ "service_mapping_info": present if mapping has been found for this device_id,device_interface_id
+ :param kwargs: For future versions:
+ bandwidth (int): value in kilobytes
+ latency (int): value in milliseconds
+ Other QoS might be passed as keyword arguments.
+ :return: tuple: ``(service_id, conn_info)`` containing:
+ - *service_uuid* (str): UUID of the established connectivity service
+ - *conn_info* (dict or None): Information to be stored at the database (or ``None``).
+ This information will be provided to the :meth:`~.edit_connectivity_service` and :obj:`~.delete`.
+ **MUST** be JSON/YAML-serializable (plain data structures).
+ :raises: SdnConnectorException: In case of error. Nothing should be created in this case.
+ Provide the parameter http_code
+ """
+ supported_service_types = {"ELINE"}
+ if service_type not in supported_service_types:
+ raise WimTapiUnsupportedServiceType(service_type, supported_service_types)
+
+ self.logger.debug("connection_points={:s}".format(str(connection_points)))
+
+ if not isinstance(connection_points, (list, tuple)):
+ raise WimTapiConnectionPointsBadFormat(connection_points)
+
+ if len(connection_points) != 2:
+ raise WimTapiConnectionPointsBadFormat(connection_points)
+
+ sips = self.tapi_client.get_service_interface_points()
+ services_composer = ServicesComposer(sips)
+
+ for connection_point in connection_points:
+ service_endpoint_id = connection_point.get("service_endpoint_id")
+ if service_endpoint_id is None:
+ raise WimTapiMissingConnPointField(
+ connection_point, "service_endpoint_id"
+ )
+
+ mapping = self.mappings.get(service_endpoint_id, {})
+ services_composer.add_service_endpoint(service_endpoint_id, mapping)
+
+ services_composer.dump(self.logger)
+
+ service_uuid, conn_info = self._create_services_and_conn_info(services_composer)
+ return service_uuid, conn_info
+
+ def _create_services_and_conn_info(self, services_composer: ServicesComposer):
+ services = services_composer.services
+ requested_capacity = services_composer.requested_capacity
+ vlan_constraint = services_composer.vlan_constraint
+
+ service_uuid = str(uuid.uuid4())
+
+ if services_composer.is_bidirectional():
+ service_endpoints = services[0]
+ self.tapi_client.create_service(
+ "<>",
+ service_uuid,
+ service_endpoints,
+ bidirectional=True,
+ requested_capacity=requested_capacity,
+ vlan_constraint=vlan_constraint,
+ )
+ conn_info = conn_info_compose_bidirectional(
+ service_uuid,
+ service_endpoints,
+ requested_capacity=requested_capacity,
+ vlan_constraint=vlan_constraint,
+ )
+
+ else:
+ service_uuid = service_uuid[0 : len(service_uuid) - 4] + "00**"
+ service_az_uuid = service_uuid.replace("**", "af")
+ service_az_endpoints = services[0]
+ service_za_uuid = service_uuid.replace("**", "fa")
+ service_za_endpoints = services[1]
+
+ self.tapi_client.create_service(
+ ">>",
+ service_az_uuid,
+ service_az_endpoints,
+ bidirectional=False,
+ requested_capacity=requested_capacity,
+ vlan_constraint=vlan_constraint,
+ )
+ self.tapi_client.create_service(
+ "<<",
+ service_za_uuid,
+ service_za_endpoints,
+ bidirectional=False,
+ requested_capacity=requested_capacity,
+ vlan_constraint=vlan_constraint,
+ )
+ conn_info = conn_info_compose_unidirectional(
+ service_az_uuid,
+ service_az_endpoints,
+ service_za_uuid,
+ service_za_endpoints,
+ requested_capacity=requested_capacity,
+ vlan_constraint=vlan_constraint,
+ )
+
+ return service_uuid, conn_info
+
+ def delete_connectivity_service(self, service_uuid, conn_info=None):
+ """
+ Disconnect multi-site endpoints previously connected
+
+ :param service_uuid: The one returned by create_connectivity_service
+ :param conn_info: The one returned by last call to 'create_connectivity_service' or 'edit_connectivity_service'
+ if they do not return None
+ :return: None
+ :raises: SdnConnectorException: In case of error. The parameter http_code must be filled
+ """
+ bidirectional = conn_info["bidirectional"]
+ if bidirectional:
+ service_uuid = conn_info["uuid"]
+ self.tapi_client.delete_service("<>", service_uuid)
+ else:
+ service_az_uuid = conn_info["az"]["uuid"]
+ service_za_uuid = conn_info["za"]["uuid"]
+ self.tapi_client.delete_service(">>", service_az_uuid)
+ self.tapi_client.delete_service("<<", service_za_uuid)
+
+ def edit_connectivity_service(
+ self, service_uuid, conn_info=None, connection_points=None, **kwargs
+ ):
+ """Change an existing connectivity service.
+
+ This method's arguments and return value follow the same convention as
+ :meth:`~.create_connectivity_service`.
+
+ :param service_uuid: UUID of the connectivity service.
+ :param conn_info: (dict or None): Information previously returned by last call to create_connectivity_service
+ or edit_connectivity_service
+ :param connection_points: (list): If provided, the old list of connection points will be replaced.
+ :param kwargs: Same meaning that create_connectivity_service
+ :return: dict or None: Information to be updated and stored at the database.
+ When ``None`` is returned, no information should be changed.
+ When an empty dict is returned, the database record will be deleted.
+ **MUST** be JSON/YAML-serializable (plain data structures).
+ Raises:
+ SdnConnectorException: In case of error.
+ """
+ raise NotImplementedError
+
+ def clear_all_connectivity_services(self):
+ """Delete all WAN Links in a WIM.
+
+ This method is intended for debugging only, and should delete all the
+ connections controlled by the WIM/SDN, not only the connections that
+ a specific RO is aware of.
+
+ Raises:
+ SdnConnectorException: In case of error.
+ """
+ raise NotImplementedError
+
+ def get_all_active_connectivity_services(self):
+ """Provide information about all active connections provisioned by a
+ WIM.
+
+ Raises:
+ SdnConnectorException: In case of error.
+ """
+ raise NotImplementedError