From 57a5d18e43313bea364732abef816830e36794ae Mon Sep 17 00:00:00 2001 From: Adit Sarfaty Date: Sun, 24 Apr 2016 12:35:32 +0300 Subject: [PATCH] NSX|V rename backend edge name when router is being renamed when exclusive/distributed router is being renamed, also rename the backed edge Change-Id: Ida0a96ec8b33d990a8ac0ba61982ec58465678c7 --- .../drivers/distributed_router_driver.py | 2 + .../nsx_v/drivers/exclusive_router_driver.py | 2 + .../nsx_v/vshield/edge_appliance_driver.py | 37 +++++++++++++++++++ .../plugins/nsx_v/vshield/edge_utils.py | 36 ++++++++++++++++-- .../plugins/nsxv/resources/backup_edges.py | 8 ++-- vmware_nsx/tests/unit/nsx_v/test_plugin.py | 25 +++++++++++++ 6 files changed, 101 insertions(+), 9 deletions(-) diff --git a/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py b/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py index f297ce506c..f6fd848d8f 100644 --- a/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py +++ b/vmware_nsx/plugins/nsx_v/drivers/distributed_router_driver.py @@ -117,6 +117,8 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver): if 'admin_state_up' in r: self.plugin._update_router_admin_state( context, router_id, self.get_type(), r['admin_state_up']) + if 'name' in r: + self.edge_manager.rename_lrouter(context, router_id, r['name']) return self.plugin.get_router(context, router_id) def delete_router(self, context, router_id): diff --git a/vmware_nsx/plugins/nsx_v/drivers/exclusive_router_driver.py b/vmware_nsx/plugins/nsx_v/drivers/exclusive_router_driver.py index c63e1c486d..b888f04ca3 100644 --- a/vmware_nsx/plugins/nsx_v/drivers/exclusive_router_driver.py +++ b/vmware_nsx/plugins/nsx_v/drivers/exclusive_router_driver.py @@ -63,6 +63,8 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver): if 'admin_state_up' in r: self.plugin._update_router_admin_state( context, router_id, self.get_type(), r['admin_state_up']) + if 'name' in r: + self.edge_manager.rename_lrouter(context, router_id, r['name']) return self.plugin.get_router(context, router_id) def detach_router(self, context, router_id, router): diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py b/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py index 6bb137643f..19923e3a81 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_appliance_driver.py @@ -26,6 +26,7 @@ from vmware_nsx.common import nsxv_constants from vmware_nsx.common import utils from vmware_nsx.plugins.nsx_v.vshield.common import constants from vmware_nsx.plugins.nsx_v.vshield.common import exceptions +from vmware_nsx.plugins.nsx_v.vshield import edge_utils from vmware_nsx.plugins.nsx_v.vshield.tasks import ( constants as task_constants) from vmware_nsx.plugins.nsx_v.vshield.tasks import tasks @@ -451,6 +452,27 @@ class EdgeApplianceDriver(object): return status + def _rename_edge(self, task): + edge_id = task.userdata['edge_id'] + LOG.debug("start rename edge %s", edge_id) + try: + # First get the current edge structure + # [0] is the status, [1] is the body + edge = self.vcns.get_edge(edge_id)[1] + # remove some data that will make the update fail + edge_utils.remove_irrelevant_keys_from_edge_request(edge) + # set the new name in the request + edge['name'] = task.userdata['name'] + # update the edge + self.vcns.update_edge(edge_id, edge) + status = task_constants.TaskStatus.COMPLETED + except exceptions.VcnsApiException as e: + LOG.error(_LE("Failed to rename edge: %s"), + e.response) + status = task_constants.TaskStatus.ERROR + + return status + def _delete_edge(self, task): edge_id = task.userdata['edge_id'] LOG.debug("VCNS: start destroying edge %s", edge_id) @@ -616,6 +638,21 @@ class EdgeApplianceDriver(object): self.task_manager.add(task) return task + def rename_edge(self, router_id, edge_id, name): + """rename edge.""" + task_name = 'rename-%s' % name + + userdata = { + 'edge_id': edge_id, + 'name': name + } + task = tasks.Task(task_name, router_id, + self._rename_edge, + userdata=userdata) + task.add_result_monitor(self.callbacks.edge_rename_result) + self.task_manager.add(task) + return task + def delete_edge(self, resource_id, edge_id, jobdata=None, dist=False): task_name = 'delete-%s' % edge_id userdata = { diff --git a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py index d25cc1a79b..8a241618d2 100644 --- a/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py +++ b/vmware_nsx/plugins/nsx_v/vshield/edge_utils.py @@ -705,14 +705,16 @@ class EdgeManager(object): router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36] self._free_edge_appliance(context, router_id) + def _build_lrouter_name(self, router_id, router_name): + return ( + router_name[:nsxv_constants.ROUTER_NAME_LENGTH - len(router_id)] + + '-' + router_id) + def create_lrouter( self, context, lrouter, lswitch=None, dist=False, appliance_size=vcns_const.SERVICE_SIZE_MAPPING['router']): """Create an edge for logical router support.""" - router_name = ( - lrouter['name'][:nsxv_constants.ROUTER_NAME_LENGTH - - len(lrouter['id'])] + - '-' + lrouter['id']) + router_name = self._build_lrouter_name(lrouter['id'], lrouter['name']) self._allocate_edge_appliance( context, lrouter['id'], router_name, appliance_size=appliance_size, @@ -721,6 +723,19 @@ class EdgeManager(object): def delete_lrouter(self, context, router_id, dist=False): self._free_edge_appliance(context, router_id) + def rename_lrouter(self, context, router_id, new_name): + binding = nsxv_db.get_nsxv_router_binding(context.session, router_id) + if not binding or not binding['edge_id']: + LOG.warning(_LW("router binding for router: %s " + "not found"), router_id) + return + edge_id = binding['edge_id'] + with locking.LockManager.get_lock(str(edge_id)): + router_name = self._build_lrouter_name(router_id, new_name) + task = self.nsxv_manager.rename_edge( + router_id, edge_id, router_name) + task.wait(task_const.TaskState.RESULT) + def update_dhcp_edge_bindings(self, context, network_id): """Reconfigure the DHCP to the edge.""" resource_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36] @@ -1672,6 +1687,16 @@ def delete_lrouter(nsxv_manager, context, router_id, dist=False): LOG.warning(_LW("router binding for router: %s not found"), router_id) +def remove_irrelevant_keys_from_edge_request(edge_request): + """Remove some unnecessary keys from the edge request. + Having these keys fail the update edge NSX transaction + """ + for key in ['status', 'datacenterMoid', 'fqdn', 'version', + 'type', 'tenant', 'datacenterName', + 'hypervisorAssist', 'universal', 'enableFips']: + edge_request.pop(key, None) + + def _retrieve_nsx_switch_id(context, network_id): """Helper method to retrieve backend switch ID.""" bindings = nsxv_db.get_network_bindings(context.session, network_id) @@ -2215,6 +2240,9 @@ class NsxVCallbacks(object): except sa_exc.NoResultFound: LOG.warning(_LW("Router Binding for %s not found"), router_id) + def edge_rename_result(self, task): + LOG.debug("edge_rename_result %d", task.status) + def interface_update_result(self, task): LOG.debug("interface_update_result %d", task.status) diff --git a/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py b/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py index 8672883464..93492c216f 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py +++ b/vmware_nsx/shell/admin/plugins/nsxv/resources/backup_edges.py @@ -26,6 +26,7 @@ from vmware_nsx.common import nsxv_constants from vmware_nsx.db import nsxv_db from vmware_nsx.db import nsxv_models from vmware_nsx.plugins.nsx_v.vshield.common import constants as vcns_const +from vmware_nsx.plugins.nsx_v.vshield import edge_utils from vmware_nsx.shell.admin.plugins.common import constants from vmware_nsx.shell.admin.plugins.common import formatters import vmware_nsx.shell.admin.plugins.common.utils as admin_utils @@ -202,11 +203,8 @@ def nsx_fix_name_mismatch(resource, event, trigger, **kwargs): LOG.info(_LI("Edge rename aborted by user")) return LOG.info(_LI("Edge rename started")) - # having these keys fail the NSX transaction - for key in ['status', 'datacenterMoid', 'fqdn', 'version', - 'type', 'tenant', 'datacenterName', - 'hypervisorAssist', 'universal', 'enableFips']: - edge.pop(key, None) + # remove some keys that will fail the NSX transaction + edge_utils.remove_irrelevant_keys_from_edge_request(edge) try: LOG.error(_LE("Update edge...")) nsxv.update_edge(edge_id, edge) diff --git a/vmware_nsx/tests/unit/nsx_v/test_plugin.py b/vmware_nsx/tests/unit/nsx_v/test_plugin.py index 57e3829843..f493375efd 100644 --- a/vmware_nsx/tests/unit/nsx_v/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v/test_plugin.py @@ -57,10 +57,13 @@ from vmware_nsx.extensions import routersize as router_size from vmware_nsx.extensions import routertype as router_type from vmware_nsx.extensions import securitygrouplogging from vmware_nsx.extensions import vnicindex as ext_vnic_idx +from vmware_nsx.plugins.nsx_v.drivers import ( + exclusive_router_driver as ex_router_driver) from vmware_nsx.plugins.nsx_v.drivers import ( shared_router_driver as router_driver) from vmware_nsx.plugins.nsx_v import md_proxy from vmware_nsx.plugins.nsx_v.vshield.common import constants as vcns_const +from vmware_nsx.plugins.nsx_v.vshield import edge_appliance_driver from vmware_nsx.plugins.nsx_v.vshield import edge_firewall_driver from vmware_nsx.plugins.nsx_v.vshield import edge_utils from vmware_nsx.plugins.nsx_v.vshield.tasks import ( @@ -2473,6 +2476,28 @@ class TestExclusiveRouterTestCase(L3NatTest, L3NatTestCaseBase, uuidutils.generate_uuid(), expected_code=webob.exc.HTTPNotFound.code) + def test_router_rename(self): + with self.router(name='old_name') as r: + with mock.patch.object(edge_appliance_driver.EdgeApplianceDriver, + 'rename_edge') as edge_rename: + new_name = 'new_name' + router_id = r['router']['id'] + # get the edge of this router + plugin = manager.NeutronManager.get_plugin() + router_obj = ex_router_driver.RouterExclusiveDriver(plugin) + ctx = context.get_admin_context() + edge_id = router_obj._get_edge_id_or_raise(ctx, router_id) + + # update the name + + body = self._update('routers', router_id, + {'router': {'name': new_name}}) + self.assertEqual(new_name, body['router']['name']) + edge_rename.assert_called_once_with( + router_id, + edge_id, + new_name + '-' + router_id) + def _test_router_update_gateway_on_l3_ext_net(self, vlan_id=None, validate_ext_gw=False, distributed=False):