diff --git a/python/neutron-understack/neutron_understack/nautobot.py b/python/neutron-understack/neutron_understack/nautobot.py index aee73aa76..77641543c 100644 --- a/python/neutron-understack/neutron_understack/nautobot.py +++ b/python/neutron-understack/neutron_understack/nautobot.py @@ -3,14 +3,19 @@ from urllib.parse import urljoin import requests +from neutron_lib import exceptions as exc from oslo_log import log from requests.models import HTTPError LOG = log.getLogger(__name__) -class NautobotError(Exception): - pass +class NautobotError(exc.NeutronException): + message = "Nautobot error" + + +class NautobotNotFoundError(NautobotError): + message = "%(obj)s not found in Nautobot. ref=%(ref)s" class Nautobot: @@ -86,6 +91,24 @@ def ucvni_delete(self, network_id): url = f"/api/plugins/undercloud-vni/ucvnis/{network_id}/" return self.make_api_request(url, "delete") + def fetch_namespace_by_name(self, name: str) -> str: + url = f"/api/ipam/namespaces/?name={name}&depth=1" + resp_data = self.make_api_request(url, "get") + try: + return resp_data["results"][0]["id"] + except (IndexError, KeyError) as error: + LOG.error("Nautobot error: %(error)s", {"error": error}) + raise NautobotNotFoundError(obj="namespace", ref=name) from error + + def namespace_create(self, name: str) -> dict: + url = "/api/ipam/namespaces/" + payload = {"name": name} + return self.make_api_request(url, "post", payload) + + def namespace_delete(self, namespace_uuid: str) -> dict: + url = f"/api/ipam/namespaces/{namespace_uuid}/" + return self.make_api_request(url, "delete") + def prep_switch_interface( self, connected_interface_id: str, ucvni_uuid: str ) -> str: diff --git a/python/neutron-understack/neutron_understack/neutron_understack_mech.py b/python/neutron-understack/neutron_understack/neutron_understack_mech.py index ec294ba68..f034be591 100644 --- a/python/neutron-understack/neutron_understack/neutron_understack_mech.py +++ b/python/neutron-understack/neutron_understack/neutron_understack_mech.py @@ -5,7 +5,6 @@ import neutron_lib.api.definitions.portbindings as portbindings from neutron_lib import constants as p_const -from neutron_lib import exceptions as exc from neutron_lib.plugins.ml2 import api from neutron_lib.plugins.ml2.api import ( MechanismDriver, @@ -130,21 +129,17 @@ def create_network_postcommit(self, context): if provider_type == p_const.TYPE_VXLAN: conf = cfg.CONF.ml2_understack ucvni_group = conf.ucvni_group - try: - self.nb.ucvni_create( - network_id, ucvni_group, network_name, segmentation_id - ) - except Exception as e: - LOG.exception( - "unable to create network %(net_id)s", {"net_id": network_id} - ) - raise exc.NetworkNotFound(net_id=network_id) from e - + self.nb.ucvni_create(network_id, ucvni_group, network_name, segmentation_id) LOG.info( "network %(net_id)s has been added on ucvni_group %(ucvni_group)s, " "physnet %(physnet)s", {"net_id": network_id, "ucvni_group": ucvni_group, "physnet": physnet}, ) + self.nb.namespace_create(name=network_id) + LOG.info( + "namespace with name %(network_id)s has been created in Nautobot", + {"network_id": network_id}, + ) def update_network_precommit(self, context): log_call("update_network_precommit", context) @@ -166,19 +161,13 @@ def delete_network_postcommit(self, context): if provider_type == p_const.TYPE_VXLAN: conf = cfg.CONF.ml2_understack ucvni_group = conf.ucvni_group - try: - self.nb.ucvni_delete(network_id) - except Exception as e: - LOG.exception( - "unable to delete network %(net_id)s", {"net_id": network_id} - ) - raise exc.NetworkNotFound(net_id=network_id) from e - + self.nb.ucvni_delete(network_id) LOG.info( "network %(net_id)s has been deleted from ucvni_group %(ucvni_group)s, " "physnet %(physnet)s", {"net_id": network_id, "ucvni_group": ucvni_group, "physnet": physnet}, ) + self._fetch_and_delete_nautobot_namespace(network_id) def create_subnet_precommit(self, context): log_call("create_subnet_precommit", context) @@ -364,3 +353,16 @@ def _delete_tenant_port_on_unbound(self, context): vlan_group_uuids=str(nb_vlan_group_id), dry_run=cfg.CONF.ml2_understack.undersync_dry_run, ) + + def _fetch_and_delete_nautobot_namespace(self, name: str) -> None: + namespace_uuid = self.nb.fetch_namespace_by_name(name) + LOG.info( + "namespace %(name)s nautobot uuid: %(ns_uuid)s", + {"name": name, "ns_uuid": namespace_uuid}, + ) + self.nb.namespace_delete(namespace_uuid) + LOG.info( + "namespace with name: %(name)s and uuid: %(ns_uuid)s has been deleted " + "from nautobot", + {"name": name, "ns_uuid": namespace_uuid}, + )