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
This commit is contained in:
Salvatore Orlando 2022-03-14 08:33:11 -07:00
parent bf62f6b953
commit c4818bcc31
7 changed files with 129 additions and 30 deletions

View File

@ -3018,8 +3018,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(

View File

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

View File

@ -903,8 +903,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,

View File

@ -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=<id>")
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=<id>")
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=<id>")
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)

View File

@ -1378,8 +1378,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)
@ -1390,8 +1390,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

View File

@ -67,6 +67,7 @@ class Operations(enum.Enum):
NSX_TAG_DEFAULT = 'nsx-tag-default'
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'
@ -286,7 +287,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,

View File

@ -995,6 +995,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,