Merge "[V2T] Helper admin utils for validation and N/S cutover"
This commit is contained in:
commit
2158636ebc
@ -18,10 +18,12 @@ import sys
|
|||||||
import netaddr
|
import netaddr
|
||||||
|
|
||||||
from neutron_lib.callbacks import registry
|
from neutron_lib.callbacks import registry
|
||||||
|
from neutron_lib import context
|
||||||
from oslo_log import log as logging
|
from oslo_log import log as logging
|
||||||
from oslo_serialization import jsonutils
|
from oslo_serialization import jsonutils
|
||||||
|
|
||||||
from vmware_nsx.shell.admin.plugins.common import constants
|
from vmware_nsx.shell.admin.plugins.common import constants
|
||||||
|
from vmware_nsx.shell.admin.plugins.common import formatters
|
||||||
from vmware_nsx.shell.admin.plugins.common import utils as admin_utils
|
from vmware_nsx.shell.admin.plugins.common import utils as admin_utils
|
||||||
from vmware_nsx.shell.admin.plugins.nsxp.resources import utils as p_utils
|
from vmware_nsx.shell.admin.plugins.nsxp.resources import utils as p_utils
|
||||||
from vmware_nsx.shell.admin.plugins.nsxv3.resources import migration
|
from vmware_nsx.shell.admin.plugins.nsxv3.resources import migration
|
||||||
@ -218,6 +220,158 @@ def migration_validate_external_cidrs(resource, event, trigger, **kwargs):
|
|||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
|
@admin_utils.output_header
|
||||||
|
@admin_utils.unpack_payload
|
||||||
|
def patch_routers_without_gateway(resource, event, trigger, **kwargs):
|
||||||
|
state_filename = None
|
||||||
|
tier0_id = None
|
||||||
|
if kwargs.get('property'):
|
||||||
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
||||||
|
state_filename = properties.get('state-file')
|
||||||
|
tier0_id = properties.get('tier0')
|
||||||
|
|
||||||
|
if not state_filename:
|
||||||
|
LOG.error("Must provide a filename for saving T1 GW state")
|
||||||
|
return
|
||||||
|
if not tier0_id:
|
||||||
|
LOG.error("Cannot execute if a Tier-0 GW uuid is not provided")
|
||||||
|
return
|
||||||
|
|
||||||
|
nsxpolicy = p_utils.get_connected_nsxpolicy()
|
||||||
|
try:
|
||||||
|
nsxpolicy.tier0.get(tier0_id)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("An error occurred while retrieving Tier0 gw router %s: %s",
|
||||||
|
tier0_id, e)
|
||||||
|
raise SystemExit(e)
|
||||||
|
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
fixed_routers = []
|
||||||
|
|
||||||
|
# Open state file, if exists, read data
|
||||||
|
try:
|
||||||
|
with open(state_filename) as f:
|
||||||
|
state_data = jsonutils.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
LOG.debug("State file not created yet")
|
||||||
|
state_data = {}
|
||||||
|
|
||||||
|
with p_utils.NsxPolicyPluginWrapper() as plugin:
|
||||||
|
routers = plugin.get_routers(ctx)
|
||||||
|
try:
|
||||||
|
for router in routers:
|
||||||
|
router_id = router['id']
|
||||||
|
if plugin._extract_external_gw(ctx, {'router': router}):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip router if already fixed up
|
||||||
|
if router_id in state_data:
|
||||||
|
LOG.info("It seems router %s has already been patched. "
|
||||||
|
"Skipping it.", router_id)
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Fetch T1
|
||||||
|
t1_data = nsxpolicy.tier1.get(router_id)
|
||||||
|
route_adv_data = t1_data.get('route_advertisement_types', [])
|
||||||
|
# append state data
|
||||||
|
state_data[router_id] = route_adv_data
|
||||||
|
# Update T1: connect to T0, disable route advertisment
|
||||||
|
nsxpolicy.tier1.update_route_advertisement(
|
||||||
|
router_id,
|
||||||
|
static_routes=False,
|
||||||
|
subnets=False,
|
||||||
|
nat=False,
|
||||||
|
lb_vip=False,
|
||||||
|
lb_snat=False,
|
||||||
|
ipsec_endpoints=False,
|
||||||
|
tier0=tier0_id)
|
||||||
|
fixed_routers.append(router)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("Failure while patching routers without "
|
||||||
|
"gateway: %s", e)
|
||||||
|
# do not call sys.exit here
|
||||||
|
finally:
|
||||||
|
# Save state data
|
||||||
|
with open(state_filename, 'w') as f:
|
||||||
|
# Pretty print in case someone needs to insepct it
|
||||||
|
jsonutils.dump(state_data, f, indent=4)
|
||||||
|
|
||||||
|
LOG.info(formatters.output_formatter(
|
||||||
|
"Attached following routers to T0 %s" % tier0_id,
|
||||||
|
fixed_routers,
|
||||||
|
['id', 'name', 'project_id']))
|
||||||
|
return fixed_routers
|
||||||
|
|
||||||
|
|
||||||
|
@admin_utils.output_header
|
||||||
|
@admin_utils.unpack_payload
|
||||||
|
def restore_routers_without_gateway(resource, event, trigger, **kwargs):
|
||||||
|
state_filename = None
|
||||||
|
if kwargs.get('property'):
|
||||||
|
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
||||||
|
state_filename = properties.get('state-file')
|
||||||
|
|
||||||
|
if not state_filename:
|
||||||
|
LOG.error("Must provide a filename for saving T1 GW state")
|
||||||
|
return
|
||||||
|
|
||||||
|
nsxpolicy = p_utils.get_connected_nsxpolicy()
|
||||||
|
ctx = context.get_admin_context()
|
||||||
|
restored_routers = []
|
||||||
|
|
||||||
|
# Open state file,read data
|
||||||
|
# Fail if file does not exist
|
||||||
|
try:
|
||||||
|
with open(state_filename) as f:
|
||||||
|
state_data = jsonutils.load(f)
|
||||||
|
except FileNotFoundError:
|
||||||
|
LOG.error("State file %s was not found. Aborting", state_filename)
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
with p_utils.NsxPolicyPluginWrapper() as plugin:
|
||||||
|
routers = plugin.get_routers(ctx)
|
||||||
|
try:
|
||||||
|
for router in routers:
|
||||||
|
router_id = router['id']
|
||||||
|
if plugin._extract_external_gw(ctx, {'router': router}):
|
||||||
|
continue
|
||||||
|
|
||||||
|
adv_info = state_data.get(router_id)
|
||||||
|
# Disconnect T0, set route adv from state file
|
||||||
|
if adv_info:
|
||||||
|
nsxpolicy.tier1.update_route_advertisement(
|
||||||
|
router_id,
|
||||||
|
static_routes=("TIER1_STATIC_ROUTES" in adv_info),
|
||||||
|
subnets=("TIER1_CONNECTED" in adv_info),
|
||||||
|
nat=("TIER1_NAT" in adv_info),
|
||||||
|
lb_vip=("TIER1_LB_VIP" in adv_info),
|
||||||
|
lb_snat=("TIER1_LB_SNAT" in adv_info),
|
||||||
|
ipsec_endpoints=("TIER1_IPSEC_LOCAL_ENDPOINT" in
|
||||||
|
adv_info),
|
||||||
|
tier0=None)
|
||||||
|
else:
|
||||||
|
# Only disconnect T0
|
||||||
|
LOG.info("Router advertisment info not found in state "
|
||||||
|
"file for router %s", router_id)
|
||||||
|
nsxpolicy.tier1.update_route_advertisement(
|
||||||
|
router_id, tier0=None)
|
||||||
|
|
||||||
|
state_data.pop(router_id, None)
|
||||||
|
restored_routers.append(router)
|
||||||
|
except Exception as e:
|
||||||
|
LOG.error("Failure while restoring routers without "
|
||||||
|
"gateway: %s", e)
|
||||||
|
finally:
|
||||||
|
with open(state_filename, 'w') as f:
|
||||||
|
# Pretty print in case someone needs to insepct it
|
||||||
|
jsonutils.dump(state_data, f, indent=4)
|
||||||
|
LOG.info(formatters.output_formatter(
|
||||||
|
"Restored following routers",
|
||||||
|
restored_routers,
|
||||||
|
['id', 'name', 'project_id']))
|
||||||
|
return restored_routers
|
||||||
|
|
||||||
|
|
||||||
registry.subscribe(cleanup_db_mappings,
|
registry.subscribe(cleanup_db_mappings,
|
||||||
constants.NSX_MIGRATE_T_P,
|
constants.NSX_MIGRATE_T_P,
|
||||||
shell.Operations.CLEAN_ALL.value)
|
shell.Operations.CLEAN_ALL.value)
|
||||||
@ -233,3 +387,11 @@ registry.subscribe(migration_tier0_redistribute,
|
|||||||
registry.subscribe(migration_validate_external_cidrs,
|
registry.subscribe(migration_validate_external_cidrs,
|
||||||
constants.NSX_MIGRATE_V_T,
|
constants.NSX_MIGRATE_V_T,
|
||||||
shell.Operations.VALIDATE.value)
|
shell.Operations.VALIDATE.value)
|
||||||
|
|
||||||
|
registry.subscribe(patch_routers_without_gateway,
|
||||||
|
constants.NSX_MIGRATE_V_T,
|
||||||
|
shell.Operations.PATCH_RTR_NOGW.value)
|
||||||
|
|
||||||
|
registry.subscribe(restore_routers_without_gateway,
|
||||||
|
constants.NSX_MIGRATE_V_T,
|
||||||
|
shell.Operations.RESTORE_RTR_NOGW.value)
|
||||||
|
@ -650,6 +650,29 @@ def list_ports_vif_ids(resource, event, trigger, **kwargs):
|
|||||||
LOG.info("Mapping data saved into %s", filename)
|
LOG.info("Mapping data saved into %s", filename)
|
||||||
|
|
||||||
|
|
||||||
|
@admin_utils.output_header
|
||||||
|
@admin_utils.unpack_payload
|
||||||
|
def get_routers_without_interfaces(resource, event, trigger, **kwargs):
|
||||||
|
context = n_context.get_admin_context()
|
||||||
|
empty_routers = []
|
||||||
|
with utils.NsxVPluginWrapper() as plugin:
|
||||||
|
routers = plugin.get_routers(context)
|
||||||
|
for router in routers:
|
||||||
|
# Routers in the metadata internal project will always have an
|
||||||
|
# interface, but it won't be returned by the method below, since
|
||||||
|
# the device_owner is network:md_interface
|
||||||
|
if router['project_id'] == 'metadata_internal_project':
|
||||||
|
LOG.debug("Skipping internal router %s", router['id'])
|
||||||
|
continue
|
||||||
|
interfaces = plugin._get_router_interfaces(router['id'])
|
||||||
|
if not interfaces:
|
||||||
|
empty_routers.append(router)
|
||||||
|
LOG.info(formatters.output_formatter(
|
||||||
|
"Routers without interfaces", empty_routers,
|
||||||
|
['id', 'name', 'project_id']))
|
||||||
|
return empty_routers
|
||||||
|
|
||||||
|
|
||||||
@admin_utils.output_header
|
@admin_utils.output_header
|
||||||
@admin_utils.unpack_payload
|
@admin_utils.unpack_payload
|
||||||
def build_edge_mapping_file(resource, event, trigger, **kwargs):
|
def build_edge_mapping_file(resource, event, trigger, **kwargs):
|
||||||
@ -686,6 +709,10 @@ def build_edge_mapping_file(resource, event, trigger, **kwargs):
|
|||||||
LOG.info("Edge mapping data saved into %s", filename)
|
LOG.info("Edge mapping data saved into %s", filename)
|
||||||
|
|
||||||
|
|
||||||
|
registry.subscribe(get_routers_without_interfaces,
|
||||||
|
constants.NSX_MIGRATE_V_T,
|
||||||
|
shell.Operations.LIST_RTR_NO_IFACE.value)
|
||||||
|
|
||||||
registry.subscribe(validate_config_for_migration,
|
registry.subscribe(validate_config_for_migration,
|
||||||
constants.NSX_MIGRATE_V_T,
|
constants.NSX_MIGRATE_V_T,
|
||||||
shell.Operations.VALIDATE.value)
|
shell.Operations.VALIDATE.value)
|
||||||
|
@ -85,6 +85,9 @@ class Operations(enum.Enum):
|
|||||||
SET_STATUS_ERROR = 'set-status-error'
|
SET_STATUS_ERROR = 'set-status-error'
|
||||||
CHECK_COMPUTE_CLUSTERS = 'check-compute-clusters'
|
CHECK_COMPUTE_CLUSTERS = 'check-compute-clusters'
|
||||||
CUTOVER_MAPPINGS = 'mappings-for-edge-cutover'
|
CUTOVER_MAPPINGS = 'mappings-for-edge-cutover'
|
||||||
|
LIST_RTR_NO_IFACE = 'list-routers-no-interfaces'
|
||||||
|
PATCH_RTR_NOGW = 'cutover-fixup-router-nogw'
|
||||||
|
RESTORE_RTR_NOGW = 'cutover-restore-router-nogw'
|
||||||
|
|
||||||
|
|
||||||
ops = [op.value for op in Operations]
|
ops = [op.value for op in Operations]
|
||||||
@ -270,7 +273,8 @@ nsxv_resources = {
|
|||||||
Operations.DELETE.value]),
|
Operations.DELETE.value]),
|
||||||
constants.NSX_MIGRATE_V_T: Resource(constants.NSX_MIGRATE_V_T,
|
constants.NSX_MIGRATE_V_T: Resource(constants.NSX_MIGRATE_V_T,
|
||||||
[Operations.VALIDATE.value,
|
[Operations.VALIDATE.value,
|
||||||
Operations.CUTOVER_MAPPINGS.value]),
|
Operations.CUTOVER_MAPPINGS.value,
|
||||||
|
Operations.LIST_RTR_NO_IFACE.value]),
|
||||||
constants.PORTS: Resource(constants.PORTS,
|
constants.PORTS: Resource(constants.PORTS,
|
||||||
[Operations.LIST.value]),
|
[Operations.LIST.value]),
|
||||||
constants.LOADBALANCERS: Resource(constants.LOADBALANCERS,
|
constants.LOADBALANCERS: Resource(constants.LOADBALANCERS,
|
||||||
@ -317,7 +321,9 @@ nsxp_resources = {
|
|||||||
constants.NSX_MIGRATE_V_T: Resource(constants.NSX_MIGRATE_V_T,
|
constants.NSX_MIGRATE_V_T: Resource(constants.NSX_MIGRATE_V_T,
|
||||||
[Operations.CLEAN_ALL.value,
|
[Operations.CLEAN_ALL.value,
|
||||||
Operations.VALIDATE.value,
|
Operations.VALIDATE.value,
|
||||||
Operations.NSX_REDISTRIBUTE.value]),
|
Operations.NSX_REDISTRIBUTE.value,
|
||||||
|
Operations.PATCH_RTR_NOGW.value,
|
||||||
|
Operations.RESTORE_RTR_NOGW.value]),
|
||||||
constants.LOADBALANCERS: Resource(constants.LOADBALANCERS,
|
constants.LOADBALANCERS: Resource(constants.LOADBALANCERS,
|
||||||
[Operations.SET_STATUS_ERROR.value]),
|
[Operations.SET_STATUS_ERROR.value]),
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user