[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
This commit is contained in:
Adit Sarfaty 2016-07-13 17:25:03 +03:00
parent 16bab8947d
commit aba3ade22f
5 changed files with 153 additions and 5 deletions

View File

@ -83,6 +83,12 @@ DHCP Bindings
nsxadmin -r dhcp-binding -o nsx-recreate --property edge-id=edge-222 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 Networks
~~~~~~~~ ~~~~~~~~

View File

@ -143,6 +143,12 @@ def get_edge_availability_zone(session, edge_id):
return binding['availability_zone'] 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): def get_edge_vnic_binding(session, edge_id, network_id):
return session.query(nsxv_models.NsxvEdgeVnicBinding).filter_by( return session.query(nsxv_models.NsxvEdgeVnicBinding).filter_by(
edge_id=edge_id, network_id=network_id).first() edge_id=edge_id, network_id=network_id).first()

View File

@ -1547,16 +1547,14 @@ class EdgeManager(object):
except Exception: except Exception:
LOG.warning(_LW("Failed to delete virtual wire: %s"), lswitch_id) LOG.warning(_LW("Failed to delete virtual wire: %s"), lswitch_id)
def get_routers_on_same_edge(self, context, router_id): def get_routers_on_edge(self, context, edge_id):
edge_binding = nsxv_db.get_nsxv_router_binding(
context.session, router_id)
router_ids = [] router_ids = []
valid_router_ids = [] valid_router_ids = []
if edge_binding: if edge_id:
router_ids = [ router_ids = [
binding['router_id'] binding['router_id']
for binding in nsxv_db.get_nsxv_router_bindings_by_edge( for binding in nsxv_db.get_nsxv_router_bindings_by_edge(
context.session, edge_binding['edge_id'])] context.session, edge_id)]
if router_ids: if router_ids:
valid_router_ids = self.plugin.get_routers( valid_router_ids = self.plugin.get_routers(
context.elevated(), context.elevated(),
@ -1570,6 +1568,13 @@ class EdgeManager(object):
str(set(router_ids) - set(valid_router_ids))) str(set(router_ids) - set(valid_router_ids)))
return 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( def bind_router_on_available_edge(
self, context, target_router_id, self, context, target_router_id,
optional_router_ids, conflict_router_ids, optional_router_ids, conflict_router_ids,

View File

@ -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)

View File

@ -125,6 +125,8 @@ nsxv_resources = {
Operations.NSX_UPDATE_SECRET.value]), Operations.NSX_UPDATE_SECRET.value]),
constants.LBAAS: Resource(constants.LBAAS, constants.LBAAS: Resource(constants.LBAAS,
[Operations.NSX_MIGRATE_V1_V2.value]), [Operations.NSX_MIGRATE_V1_V2.value]),
constants.ROUTERS: Resource(constants.ROUTERS,
[Operations.NSX_RECREATE.value]),
} }
nsxv3_resources_names = list(nsxv3_resources.keys()) nsxv3_resources_names = list(nsxv3_resources.keys())