From aba3ade22f215d5e9a64afa253328e22a579f329 Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Wed, 13 Jul 2016 17:25:03 +0300 Subject: [PATCH] [Admin-Util] recreate NSX|v router edge Delete a backend router edge, and move its' router/s to other edges. Currently this utility does not support distributed routers usage: nsxadmin -r routers -o nsx-recreate --property edge-id=edge-307 Change-Id: Ib1ab84120aaae42dba884d4ba964a3bdd82df2fb --- doc/source/admin_util.rst | 6 + vmware_nsx/db/nsxv_db.py | 6 + .../plugins/nsx_v/vshield/edge_utils.py | 15 +- .../admin/plugins/nsxv/resources/routers.py | 129 ++++++++++++++++++ vmware_nsx/shell/resources.py | 2 + 5 files changed, 153 insertions(+), 5 deletions(-) create mode 100644 vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py diff --git a/doc/source/admin_util.rst b/doc/source/admin_util.rst index 0cc81cdaf4..968ae59db4 100644 --- a/doc/source/admin_util.rst +++ b/doc/source/admin_util.rst @@ -83,6 +83,12 @@ DHCP Bindings nsxadmin -r dhcp-binding -o nsx-recreate --property edge-id=edge-222 +Routers +~~~~~~~ +- Recreate a router edge by moving the router/s to other edge/s:: + + nsxadmin -r routers -o nsx-recreate --property edge-id=edge-308 + Networks ~~~~~~~~ diff --git a/vmware_nsx/db/nsxv_db.py b/vmware_nsx/db/nsxv_db.py index 5ee6273293..45f85a75a8 100644 --- a/vmware_nsx/db/nsxv_db.py +++ b/vmware_nsx/db/nsxv_db.py @@ -143,6 +143,12 @@ def get_edge_availability_zone(session, edge_id): return binding['availability_zone'] +def clean_edge_router_binding(session, edge_id): + with session.begin(subtransactions=True): + (session.query(nsxv_models.NsxvRouterBinding). + filter_by(edge_id=edge_id).delete()) + + def get_edge_vnic_binding(session, edge_id, network_id): return session.query(nsxv_models.NsxvEdgeVnicBinding).filter_by( edge_id=edge_id, network_id=network_id).first() diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py index a7aa2ddb40..8b6cda1c8b 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py @@ -1547,16 +1547,14 @@ class EdgeManager(object): except Exception: LOG.warning(_LW("Failed to delete virtual wire: %s"), lswitch_id) - def get_routers_on_same_edge(self, context, router_id): - edge_binding = nsxv_db.get_nsxv_router_binding( - context.session, router_id) + def get_routers_on_edge(self, context, edge_id): router_ids = [] valid_router_ids = [] - if edge_binding: + if edge_id: router_ids = [ binding['router_id'] for binding in nsxv_db.get_nsxv_router_bindings_by_edge( - context.session, edge_binding['edge_id'])] + context.session, edge_id)] if router_ids: valid_router_ids = self.plugin.get_routers( context.elevated(), @@ -1570,6 +1568,13 @@ class EdgeManager(object): str(set(router_ids) - set(valid_router_ids))) return valid_router_ids + def get_routers_on_same_edge(self, context, router_id): + edge_binding = nsxv_db.get_nsxv_router_binding( + context.session, router_id) + if edge_binding: + return self.get_routers_on_edge(context, edge_binding['edge_id']) + return [] + def bind_router_on_available_edge( self, context, target_router_id, optional_router_ids, conflict_router_ids, diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py new file mode 100644 index 0000000000..cded6e1bc5 --- /dev/null +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/routers.py @@ -0,0 +1,129 @@ +# Copyright 2016 VMware, Inc. All rights reserved. +# +# 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. + + +import logging + +from vmware_nsx.shell.admin.plugins.common import constants +import vmware_nsx.shell.admin.plugins.common.utils as admin_utils +import vmware_nsx.shell.admin.plugins.nsxv.resources.utils as utils +import vmware_nsx.shell.resources as shell + +from neutron.callbacks import registry +from neutron import context as n_context +from oslo_config import cfg + +from vmware_nsx._i18n import _LE, _LI, _LW +from vmware_nsx.common import locking +from vmware_nsx.db import nsxv_db +from vmware_nsx.extensions import routersize +from vmware_nsx.plugins.nsx_v.vshield import edge_utils +from vmware_nsx.plugins.nsx_v.vshield import vcns_driver + +LOG = logging.getLogger(__name__) + + +def delete_old_edge(context, old_edge_id): + LOG.info(_LI("Deleting the old edge: %s"), old_edge_id) + + # clean it up from the DB + nsxv_db.clean_edge_router_binding(context.session, old_edge_id) + nsxv_db.clean_edge_vnic_binding(context.session, old_edge_id) + nsxv_db.cleanup_nsxv_edge_firewallrule_binding(context.session, + old_edge_id) + + with locking.LockManager.get_lock(old_edge_id): + # Delete from NSXv backend + # Note - If we will not delete the edge, but free it - it will be + # immediately used as the new one, So it is better to delete it. + try: + nsxv = utils.get_nsxv_client() + nsxv.delete_edge(old_edge_id) + except Exception as e: + LOG.warning(_LW("Failed to delete the old edge %(id)s: %(e)s"), + {'id': old_edge_id, 'e': e}) + # Continue the process anyway + # The edge may have been already deleted at the backend + + +@admin_utils.output_header +def nsx_recreate_router_edge(resource, event, trigger, **kwargs): + """Recreate a router edge with all the data on a new NSXv edge""" + if not kwargs.get('property'): + LOG.error(_LE("Need to specify edge-id parameter")) + return + + # input validation + properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) + old_edge_id = properties.get('edge-id') + if not old_edge_id: + LOG.error(_LE("Need to specify edge-id parameter")) + return + LOG.info(_LI("ReCreating NSXv Router Edge: %s"), old_edge_id) + + # init the plugin and edge manager + cfg.CONF.set_override('core_plugin', + 'vmware_nsx.shell.admin.plugins.nsxv.resources' + '.utils.NsxVPluginWrapper') + plugin = utils.NsxVPluginWrapper() + nsxv_manager = vcns_driver.VcnsDriver(edge_utils.NsxVCallbacks(plugin)) + edge_manager = edge_utils.EdgeManager(nsxv_manager, plugin) + context = n_context.get_admin_context() + + # verify that this is a Router edge + router_ids = edge_manager.get_routers_on_edge(context, old_edge_id) + if not router_ids: + LOG.error(_LE("Edge %(edge_id)s is not a router edge"), + {'edge_id': old_edge_id}) + return + + # all the routers on the same edge have the same type, so it + # is ok to check the type once + example_router = plugin.get_router(context, router_ids[0]) + router_driver = plugin._router_managers.get_tenant_router_driver( + context, example_router['router_type']) + if router_driver.get_type() == "distributed": + LOG.error(_LE("Recreating a distributed driver edge is not " + "supported")) + return + + # load all the routers before deleting their binding + routers = [] + for router_id in router_ids: + routers.append(plugin.get_router(context, router_id)) + + # delete the backend edge and all the relevant DB entries + delete_old_edge(context, old_edge_id) + + # Go over all the relevant routers + for router in routers: + router_id = router['id'] + # clean up other objects related to this router + if plugin.metadata_proxy_handler: + plugin.metadata_proxy_handler.cleanup_router_edge(router_id) + + # attach the router to a new edge + appliance_size = router.get(routersize.ROUTER_SIZE) + router_driver.attach_router(context, router_id, + {'router': router}, + appliance_size=appliance_size) + # find out who is the new edge to print it + new_edge_id = router_driver._get_edge_id_or_raise(context, router_id) + LOG.info(_LI("Router %(router)s was attached to edge %(edge)s"), + {'router': router_id, 'edge': new_edge_id}) + + +registry.subscribe(nsx_recreate_router_edge, + constants.ROUTERS, + shell.Operations.NSX_RECREATE.value) diff --git a/vmware_nsx/shell/resources.py b/vmware_nsx/shell/resources.py index c1508ad963..c3b69ea274 100644 --- a/vmware_nsx/shell/resources.py +++ b/vmware_nsx/shell/resources.py @@ -125,6 +125,8 @@ nsxv_resources = { Operations.NSX_UPDATE_SECRET.value]), constants.LBAAS: Resource(constants.LBAAS, [Operations.NSX_MIGRATE_V1_V2.value]), + constants.ROUTERS: Resource(constants.ROUTERS, + [Operations.NSX_RECREATE.value]), } nsxv3_resources_names = list(nsxv3_resources.keys())