From 85e77c23779d2d53879fe1be335e27a7e94a7631 Mon Sep 17 00:00:00 2001 From: Salvatore Orlando Date: Mon, 14 Mar 2022 08:33:11 -0700 Subject: [PATCH] Fix migration of DHCP to NSX policy Ensure DHCP bindings are properly created for existing Neutron ports when DHCP is enabled on NSX Policy. Enhance output to report list of skipped and failed networks. Also, add an utility for regenerating bindings post-migration. Finally, this change removes some debug log statements, and makes some changes to satisfy pylint checks for error E0601. Change-Id: Idc6870d5a7896f9b9aeda2ea2f102a59b13eb523 --- vmware_nsx/plugins/nsx_p/plugin.py | 2 +- vmware_nsx/plugins/nsx_v/plugin.py | 2 + vmware_nsx/plugins/nsx_v3/plugin.py | 3 +- .../admin/plugins/nsxp/resources/networks.py | 137 +++++++++++++++--- .../plugins/nsxv3/resources/migration.py | 8 +- vmware_nsx/shell/resources.py | 4 +- vmware_nsx/tests/unit/nsx_v3/test_plugin.py | 3 + 7 files changed, 129 insertions(+), 30 deletions(-) diff --git a/vmware_nsx/plugins/nsx_p/plugin.py b/vmware_nsx/plugins/nsx_p/plugin.py index f8855ef790..ba801f5448 100644 --- a/vmware_nsx/plugins/nsx_p/plugin.py +++ b/vmware_nsx/plugins/nsx_p/plugin.py @@ -3029,8 +3029,8 @@ class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base): context, router_id, router) # Update the policy backend + added_routes = removed_routes = False try: - added_routes = removed_routes = False # Updating name & description if 'name' in router_data or 'description' in router_data: router_name = utils.get_name_and_uuid( diff --git a/vmware_nsx/plugins/nsx_v/plugin.py b/vmware_nsx/plugins/nsx_v/plugin.py index 2d377012b4..35ddc17bab 100644 --- a/vmware_nsx/plugins/nsx_v/plugin.py +++ b/vmware_nsx/plugins/nsx_v/plugin.py @@ -1356,6 +1356,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin, dvs_pg_mappings): self._delete_backend_network( netmoref, dvsmoref) + # Define variable to satisfy pylint check (E0601) + predefined = None try: net_data[psec.PORTSECURITY] = net_data.get(psec.PORTSECURITY, True) if not cfg.CONF.nsxv.spoofguard_enabled: diff --git a/vmware_nsx/plugins/nsx_v3/plugin.py b/vmware_nsx/plugins/nsx_v3/plugin.py index 98a717a63a..51c9e6d05d 100644 --- a/vmware_nsx/plugins/nsx_v3/plugin.py +++ b/vmware_nsx/plugins/nsx_v3/plugin.py @@ -935,8 +935,9 @@ class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base, vlt)) is_backend_network = True + # Define variable here to avoid pylint E0601 + rollback_network = False try: - rollback_network = False with db_api.CONTEXT_WRITER.using(context): # Create network in Neutron created_net = super(NsxV3Plugin, self).create_network(context, diff --git a/vmware_nsx/shell/admin/plugins/nsxp/resources/networks.py b/vmware_nsx/shell/admin/plugins/nsxp/resources/networks.py index caf3015cf4..c1d597ff57 100644 --- a/vmware_nsx/shell/admin/plugins/nsxp/resources/networks.py +++ b/vmware_nsx/shell/admin/plugins/nsxp/resources/networks.py @@ -54,14 +54,7 @@ def list_networks(resource, event, trigger, **kwargs): return bool(mappings) -@admin_utils.output_header -def migrate_dhcp_to_policy(resource, event, trigger, **kwargs): - errmsg = ("Need to specify policy dhcp config id. Add " - "--property dhcp-config=") - if not kwargs.get('property'): - LOG.error("%s", errmsg) - return - properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) +def _validate_dhcp_operation(properties, nsxpolicy, errmsg): dhcp_config_id = properties.get('dhcp-config') if not dhcp_config_id: LOG.error("%s", errmsg) @@ -79,11 +72,115 @@ def migrate_dhcp_to_policy(resource, event, trigger, **kwargs): except Exception: LOG.error("%s", errmsg) return + return dhcp_config_id + +@admin_utils.output_header +def migrate_dhcp_to_policy(resource, event, trigger, **kwargs): + errmsg = ("Need to specify policy dhcp profile id. Add " + "--property dhcp-config=") + if not kwargs.get('property'): + LOG.error("%s", errmsg) + return + properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) + nsxpolicy = p_utils.get_connected_nsxpolicy() + dhcp_config_id = _validate_dhcp_operation(properties, nsxpolicy, errmsg) + if not dhcp_config_id: + LOG.error("Unable to proceed. Please address errors and retry.") + return + + ctx = context.get_admin_context() + migrated_networks = [] + skipped_networks = [] + failed_networks = {} + with p_utils.NsxPolicyPluginWrapper() as plugin: + nets = plugin.get_networks(ctx) + for net in nets: + # skip non-dhcp networks + subnets = plugin._get_subnets_by_network(ctx, net['id']) + dhcp_subnet_id = None + for subnet in subnets: + if subnet['enable_dhcp']: + dhcp_subnet_id = subnet['id'] + break + if not dhcp_subnet_id: + LOG.info("Skipping network %s: No DHCP subnet found", + net['id']) + skipped_networks.append(net['id']) + continue + az = plugin.get_network_az_by_net_id(ctx, net['id']) + az._policy_dhcp_server_config = dhcp_config_id + dhcp_subnet = plugin.get_subnet(ctx, dhcp_subnet_id) + + # Verify that this network does not use policy DHCP already + segment_id = plugin._get_network_nsx_segment_id(ctx, net['id']) + segment = nsxpolicy.segment.get(segment_id) + if segment.get('dhcp_config_path'): + LOG.info("Skipping network %s: Already using policy DHCP", + net['id']) + skipped_networks.append(net['id']) + continue + + LOG.info("Migrating network %s", net['id']) + try: + # Disable MP DHCP + plugin._disable_native_dhcp(ctx, net['id']) + # Enable Policy DHCP, restore bindings + plugin._update_nsx_net_dhcp(ctx, net, az, dhcp_subnet) + LOG.info("Successfully migrated network %s", net['id']) + except Exception as e: + LOG.error("Failure while migrating network %s: %s", + net['id'], e) + failed_networks[net['id']] = e + migrated_networks.append(net['id']) + + if not failed_networks and not skipped_networks: + LOG.info("DHCP for %s networks has been migrated to policy", + len(migrated_networks)) + return + # Some networks were skipped or failed. Log everything + mappings = [] + for net_id in migrated_networks: + mappings.append({ + 'net': net_id, + 'status': 'MIGRATED', + 'details': ''}) + for net_id in skipped_networks: + mappings.append({ + 'net': net_id, + 'status': 'SKIPPED', + 'details': ''}) + for net_id, exc in failed_networks.items(): + mappings.append({ + 'net': net_id, + 'status': 'FAILED', + 'details': str(exc)}) + p_utils.log_info(constants.NETWORKS, + mappings, + attrs=['net', 'status', 'details']) + + +@admin_utils.output_header +def restore_dhcp_to_policy(resource, event, trigger, **kwargs): + errmsg = ("Need to specify policy dhcp config id. Add " + "--property dhcp-config=") + if not kwargs.get('property'): + LOG.error("%s", errmsg) + return + properties = admin_utils.parse_multi_keyval_opt(kwargs['property']) + nsxpolicy = p_utils.get_connected_nsxpolicy() + dhcp_config_id = _validate_dhcp_operation(properties, nsxpolicy, errmsg) + if not dhcp_config_id: + LOG.error("Unable to proceed. Please address errors and retry.") + return + network_id = properties.get('network-id') ctx = context.get_admin_context() migrate_count = 0 with p_utils.NsxPolicyPluginWrapper() as plugin: - nets = plugin.get_networks(ctx) + if network_id: + nets = [plugin.get_network(ctx, network_id)] + else: + nets = plugin.get_networks(ctx) for net in nets: # skip non-dhcp networks dhcp_port = plugin._get_net_dhcp_port(ctx, net['id']) @@ -97,22 +194,12 @@ def migrate_dhcp_to_policy(resource, event, trigger, **kwargs): az._policy_dhcp_server_config = dhcp_config_id dhcp_subnet = plugin.get_subnet(ctx, dhcp_subnet_id) - # Verify that this network does not use policy DHCP already - segment_id = plugin._get_network_nsx_segment_id(ctx, net['id']) - segment = nsxpolicy.segment.get(segment_id) - if segment.get('dhcp_config_path'): - LOG.info("Skipping network %s: Already using policy DHCP", - net['id']) - continue - - LOG.info("Migrating network %s", net['id']) - # Disable MP DHCP - plugin._disable_native_dhcp(ctx, net['id']) - # Enable Policy DHCP - plugin._enable_subnet_dhcp(ctx, net, dhcp_subnet, az) + LOG.info("Attempting to restore DHCP on network %s", net['id']) + # Enable Policy DHCP, restore bindings + plugin._update_nsx_net_dhcp(ctx, net, az, dhcp_subnet) migrate_count = migrate_count + 1 - LOG.info("Finished migrating %s networks", migrate_count) + LOG.info("Finished processing %s networks", migrate_count) @admin_utils.output_header @@ -150,3 +237,7 @@ registry.subscribe(update_admin_state, registry.subscribe(migrate_dhcp_to_policy, constants.DHCP_BINDING, shell.Operations.MIGRATE_TO_POLICY.value) + +registry.subscribe(restore_dhcp_to_policy, + constants.DHCP_BINDING, + shell.Operations.RESTORE_POLICY_DHCP.value) diff --git a/vmware_nsx/shell/admin/plugins/nsxv3/resources/migration.py b/vmware_nsx/shell/admin/plugins/nsxv3/resources/migration.py index 8d26765d8f..d6f6104020 100644 --- a/vmware_nsx/shell/admin/plugins/nsxv3/resources/migration.py +++ b/vmware_nsx/shell/admin/plugins/nsxv3/resources/migration.py @@ -1380,8 +1380,8 @@ def migrate_t_resources_2_p(nsxlib, nsxpolicy, plugin, LOG.info("Aborting the current request") try: send_migration_plan_action(nsxlib, 'abort') - except Exception as e: - LOG.error("Abort migration failed: %s", e) + except Exception as e2: + LOG.error("Abort migration failed: %s", e2) if ROLLBACK_DATA: LOG.info("Rolling migration back %s", ROLLBACK_DATA) @@ -1392,8 +1392,8 @@ def migrate_t_resources_2_p(nsxlib, nsxpolicy, plugin, # Stop the migration service if start_migration_service: change_migration_service_status(start=False) - except Exception as e: - LOG.error("Rollback failed: %s", e) + except Exception as e2: + LOG.error("Rollback failed: %s", e2) return False diff --git a/vmware_nsx/shell/resources.py b/vmware_nsx/shell/resources.py index ecf2baa87f..369e6149f6 100644 --- a/vmware_nsx/shell/resources.py +++ b/vmware_nsx/shell/resources.py @@ -68,6 +68,7 @@ class Operations(enum.Enum): MIGRATE_TO_DYNAMIC_CRITERIA = 'migrate-to-dynamic-criteria' NSX_MIGRATE_V_V3 = 'nsx-migrate-v-v3' MIGRATE_TO_POLICY = 'migrate-to-policy' + RESTORE_POLICY_DHCP = 'restore-policy-dhcp' LIST_POLICIES = 'list-policies' UPDATE_LOGGING = 'update-logging' NSX_MIGRATE_EXCLUDE_PORTS = 'migrate-exclude-ports' @@ -296,7 +297,8 @@ nsxp_resources = { [Operations.LIST.value, Operations.NSX_UPDATE_STATE.value]), constants.DHCP_BINDING: Resource(constants.DHCP_BINDING, - [Operations.MIGRATE_TO_POLICY.value]), + [Operations.MIGRATE_TO_POLICY.value, + Operations.RESTORE_POLICY_DHCP.value]), constants.ROUTERS: Resource(constants.ROUTERS, [Operations.LIST.value, Operations.UPDATE_TIER0.value, diff --git a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py index be5b05dd86..9dc5465f3a 100644 --- a/vmware_nsx/tests/unit/nsx_v3/test_plugin.py +++ b/vmware_nsx/tests/unit/nsx_v3/test_plugin.py @@ -1036,6 +1036,9 @@ class TestSubnetsV2(common_v3.NsxV3TestSubnets, NsxV3PluginTestCaseMixin): def test_create_subnet_ipv6_slaac_with_db_reference_error(self): self.skipTest('No DHCP v6 Support yet') + def test_update_subnet_the_same_gw_as_in_use_by_router_ipv6(self): + self.skipTest('No DHCP v6 Support yet') + class TestPortsV2(common_v3.NsxV3SubnetMixin, common_v3.NsxV3TestPorts, NsxV3PluginTestCaseMixin,