From e2a50078845a5d67ca3fe1c5a64d0cc530c18339 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Sun, 14 Jul 2019 11:03:05 +0300 Subject: [PATCH] NSX|V3+P: Admin utility to replace tier0 Replace an old tier0 (that might have been deleted) with a new one Usage: nsxadmin -r routers -o update-tier0 --property old-tier0= --property new-tier0= Change-Id: I83200508b827586cb0a404f43ac7ec23966d1675 --- doc/source/admin_util.rst | 8 ++ .../admin/plugins/nsxp/resources/routers.py | 75 +++++++++++++++ .../admin/plugins/nsxv3/resources/routers.py | 91 +++++++++++++++++-- vmware_nsx/shell/resources.py | 17 ++-- 4 files changed, 178 insertions(+), 13 deletions(-) diff --git a/doc/source/admin_util.rst b/doc/source/admin_util.rst index 047e0be9b2..3572e135be 100644 --- a/doc/source/admin_util.rst +++ b/doc/source/admin_util.rst @@ -364,6 +364,10 @@ Routers nsxadmin -r routers -o nsx-enable-standby-relocation +- Replace an old tier0 (that might have been deleted) with a new one:: + + nsxadmin -r routers -o update-tier0 --property old-tier0= --property new-tier0= + Orphaned Routers ~~~~~~~~~~~~~~~~~ @@ -623,6 +627,10 @@ NSX Policy Plugin nsxadmin -r system -o set -p realization_interval=1 +- Replace an old tier0 (that might have been deleted) with a new one:: + + nsxadmin -r routers -o update-tier0 --property old-tier0= --property new-tier0= + Client Certificate ~~~~~~~~~~~~~~~~~~ diff --git a/vmware_nsx/shell/admin/plugins/nsxp/resources/routers.py b/vmware_nsx/shell/admin/plugins/nsxp/resources/routers.py index c4aed53851..ce68e7462e 100644 --- a/vmware_nsx/shell/admin/plugins/nsxp/resources/routers.py +++ b/vmware_nsx/shell/admin/plugins/nsxp/resources/routers.py @@ -12,11 +12,24 @@ # License for the specific language governing permissions and limitations # under the License. +from neutron.db import db_base_plugin_v2 +from neutron.db import l3_db +from neutron_lib.callbacks import registry from neutron_lib import context +from oslo_log import log as logging +from vmware_nsx.db import nsx_models from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import utils as admin_utils from vmware_nsx.shell.admin.plugins.nsxp.resources import utils as p_utils +from vmware_nsx.shell import resources as shell + +LOG = logging.getLogger(__name__) + + +class RoutersPlugin(db_base_plugin_v2.NeutronDbPluginV2, + l3_db.L3_NAT_db_mixin): + pass @admin_utils.list_handler(constants.ROUTERS) @@ -42,3 +55,65 @@ def list_routers(resource, event, trigger, **kwargs): mappings, attrs=['Project', 'Name', 'ID', 'NSX status']) return bool(mappings) + + +@admin_utils.output_header +def update_tier0(resource, event, trigger, **kwargs): + """Replace old tier0 with a new one on the neutron DB and NSX backend""" + errmsg = ("Need to specify old and new tier0 ID. Add --property " + "old-tier0= --property new-tier0=") + if not kwargs.get('property'): + LOG.error("%s", errmsg) + return + properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) + old_tier0 = properties.get('old-tier0') + new_tier0 = properties.get('new-tier0') + if not old_tier0 or not new_tier0: + LOG.error("%s", errmsg) + return + # Verify the id of the new tier0 (old one might not exist any more) + nsxpolicy = p_utils.get_connected_nsxpolicy() + try: + nsxpolicy.tier0.get(new_tier0) + except Exception: + LOG.error("Tier0 logical router %s was not found", new_tier0) + return + + # update all neutron DB entries + old_tier0_networks = [] + ctx = context.get_admin_context() + with ctx.session.begin(subtransactions=True): + bindings = ctx.session.query( + nsx_models.TzNetworkBinding).filter_by(phy_uuid=old_tier0).all() + for bind in bindings: + old_tier0_networks.append(bind.network_id) + bind.phy_uuid = new_tier0 + + if not old_tier0_networks: + LOG.info("Did not find any provider networks using tier0 %s", + old_tier0) + return + + LOG.info("Updated provider networks in DB: %s", old_tier0_networks) + + # Update tier1 routers GW to point to the new tier0 in the backend + plugin = RoutersPlugin() + neutron_routers = plugin.get_routers(ctx) + for router in neutron_routers: + router_gw_net = (router.get('external_gateway_info') and + router['external_gateway_info'].get('network_id')) + if router_gw_net and router_gw_net in old_tier0_networks: + try: + nsxpolicy.tier1.update(router['id'], tier0=new_tier0) + except Exception as e: + LOG.error("Failed to update router %s linked port: %s", + router['id'], e) + else: + LOG.info("Updated router %s uplink port", router['id']) + + LOG.info("Done.") + + +registry.subscribe(update_tier0, + constants.ROUTERS, + shell.Operations.UPDATE_TIER0.value) diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py index 52427c4959..5cba130bc2 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/routers.py @@ -14,8 +14,15 @@ import sys +from neutron.db import db_base_plugin_v2 +from neutron.db import l3_db +from neutron_lib.callbacks import registry +from neutron_lib import context as neutron_context +from oslo_log import log as logging + from vmware_nsx.common import utils as nsx_utils from vmware_nsx.db import db as nsx_db +from vmware_nsx.db import nsx_models from vmware_nsx.plugins.nsx_v3 import utils as v3_utils from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import formatters @@ -25,12 +32,6 @@ from vmware_nsx.shell import resources as shell from vmware_nsxlib.v3 import exceptions as nsx_exc from vmware_nsxlib.v3 import nsx_constants -from neutron.db import db_base_plugin_v2 -from neutron.db import l3_db -from neutron_lib.callbacks import registry -from neutron_lib import context as neutron_context -from oslo_log import log as logging - LOG = logging.getLogger(__name__) neutron_client = utils.NeutronDbClient() @@ -247,6 +248,79 @@ def update_dhcp_relay(resource, event, trigger, **kwargs): LOG.info("Done.") +@admin_utils.output_header +def update_tier0(resource, event, trigger, **kwargs): + """Replace old tier0 with a new one on the neutron DB and NSX backend""" + errmsg = ("Need to specify old and new tier0 ID. Add --property " + "old-tier0= --property new-tier0=") + if not kwargs.get('property'): + LOG.error("%s", errmsg) + return + properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) + old_tier0 = properties.get('old-tier0') + new_tier0 = properties.get('new-tier0') + if not old_tier0 or not new_tier0: + LOG.error("%s", errmsg) + return + # Verify the id of the new tier0 (old one might not exist any more) + nsxlib = utils.get_connected_nsxlib() + try: + tier0_obj = nsxlib.logical_router.get(new_tier0) + except Exception: + LOG.error("Tier0 logical router %s was not found", new_tier0) + return + if tier0_obj.get('router_type') != 'TIER0': + LOG.error("Logical router %s is not a tier0 router", new_tier0) + return + + # update all neutron DB entries + old_tier0_networks = [] + admin_cxt = neutron_context.get_admin_context() + with admin_cxt.session.begin(subtransactions=True): + bindings = admin_cxt.session.query( + nsx_models.TzNetworkBinding).filter_by(phy_uuid=old_tier0).all() + for bind in bindings: + old_tier0_networks.append(bind.network_id) + bind.phy_uuid = new_tier0 + + if not old_tier0_networks: + LOG.info("Did not find any provider networks using tier0 %s", + old_tier0) + return + + LOG.info("Updated provider networks in DB: %s", old_tier0_networks) + + # Update tier1 routers GW to point to the new tier0 in the backend + plugin = RoutersPlugin() + filters = utils.get_plugin_filters(admin_cxt) + neutron_routers = plugin.get_routers(admin_cxt, filters=filters) + for router in neutron_routers: + router_gw_net = (router.get('external_gateway_info') and + router['external_gateway_info'].get('network_id')) + if router_gw_net and router_gw_net in old_tier0_networks: + nsx_router_id = nsx_db.get_nsx_router_id( + admin_cxt.session, router['id']) + try: + nsxlib.router.remove_router_link_port(nsx_router_id) + except Exception as e: + LOG.info("Could not delete router %s linked port: %s", + router['id'], e) + tags = nsxlib.build_v3_tags_payload( + router, resource_type='os-neutron-rport', + project_name=admin_cxt.tenant_name) + try: + nsxlib.router.add_router_link_port(nsx_router_id, + new_tier0, + tags=tags) + except Exception as e: + LOG.error("Failed to create router %s linked port: %s", + router['id'], e) + else: + LOG.info("Updated router %s uplink port", router['id']) + + LOG.info("Done.") + + registry.subscribe(list_missing_routers, constants.ROUTERS, shell.Operations.LIST_MISMATCHES.value) @@ -266,6 +340,11 @@ registry.subscribe(delete_backend_router, registry.subscribe(update_dhcp_relay, constants.ROUTERS, shell.Operations.NSX_UPDATE_DHCP_RELAY.value) + registry.subscribe(update_enable_standby_relocation, constants.ROUTERS, shell.Operations.NSX_ENABLE_STANDBY_RELOCATION.value) + +registry.subscribe(update_tier0, + constants.ROUTERS, + shell.Operations.UPDATE_TIER0.value) diff --git a/vmware_nsx/shell/resources.py b/vmware_nsx/shell/resources.py index 6909f0d5b8..9fae34dd20 100644 --- a/vmware_nsx/shell/resources.py +++ b/vmware_nsx/shell/resources.py @@ -71,6 +71,7 @@ class Operations(enum.Enum): SHOW = 'show' VALIDATE = 'validate' REUSE = 'reuse' + UPDATE_TIER0 = 'update-tier0' ops = [op.value for op in Operations] @@ -108,12 +109,13 @@ nsxv3_resources = { Operations.NSX_TAG_DEFAULT.value, Operations.NSX_MIGRATE_V_V3.value, Operations.NSX_MIGRATE_EXCLUDE_PORTS.value]), - constants.ROUTERS: Resource(constants.ROUTERS, - [Operations.LIST_MISMATCHES.value, - Operations.NSX_UPDATE_RULES.value, - Operations.NSX_UPDATE_DHCP_RELAY.value, - Operations.NSX_ENABLE_STANDBY_RELOCATION.value - ]), + constants.ROUTERS: Resource( + constants.ROUTERS, [ + Operations.LIST_MISMATCHES.value, + Operations.NSX_UPDATE_RULES.value, + Operations.NSX_UPDATE_DHCP_RELAY.value, + Operations.NSX_ENABLE_STANDBY_RELOCATION.value, + Operations.UPDATE_TIER0.value]), constants.DHCP_BINDING: Resource(constants.DHCP_BINDING, [Operations.LIST.value, Operations.NSX_UPDATE.value, @@ -257,7 +259,8 @@ nsxp_resources = { constants.NETWORKS: Resource(constants.NETWORKS, [Operations.LIST.value]), constants.ROUTERS: Resource(constants.ROUTERS, - [Operations.LIST.value]), + [Operations.LIST.value, + Operations.UPDATE_TIER0.value]), constants.CERTIFICATE: Resource(constants.CERTIFICATE, [Operations.GENERATE.value, Operations.SHOW.value,