V2T migration: more validations
- Warn about non neutron edges - Check that the subnet gateway IP belong to the cidr - Fix validation for direct vnic ports - Code refactor Change-Id: I40795b987da123e75179817ec3c507b92f72eb81
This commit is contained in:
parent
2db57b4651
commit
2367ad487c
@ -69,15 +69,10 @@ def extend_edge_info(edges):
|
|||||||
edge['syslog'] = utils.get_edge_syslog_info(edge['id'])
|
edge['syslog'] = utils.get_edge_syslog_info(edge['id'])
|
||||||
|
|
||||||
|
|
||||||
def get_router_edge_bindings():
|
|
||||||
edgeapi = utils.NeutronDbClient()
|
|
||||||
return nsxv_db.get_nsxv_router_bindings(edgeapi.context)
|
|
||||||
|
|
||||||
|
|
||||||
@admin_utils.output_header
|
@admin_utils.output_header
|
||||||
def neutron_list_router_edge_bindings(resource, event, trigger, **kwargs):
|
def neutron_list_router_edge_bindings(resource, event, trigger, **kwargs):
|
||||||
"""List NSXv edges from Neutron DB"""
|
"""List NSXv edges from Neutron DB"""
|
||||||
edges = get_router_edge_bindings()
|
edges = utils.get_router_edge_bindings()
|
||||||
LOG.info(formatters.output_formatter(
|
LOG.info(formatters.output_formatter(
|
||||||
constants.EDGES, edges,
|
constants.EDGES, edges,
|
||||||
['edge_id', 'router_id', 'availability_zone', 'status']))
|
['edge_id', 'router_id', 'availability_zone', 'status']))
|
||||||
@ -142,7 +137,7 @@ def get_orphaned_router_bindings():
|
|||||||
if plr_id:
|
if plr_id:
|
||||||
plr_tlr_ids[plr_id] = tlr_id
|
plr_tlr_ids[plr_id] = tlr_id
|
||||||
|
|
||||||
for binding in get_router_edge_bindings():
|
for binding in utils.get_router_edge_bindings():
|
||||||
if not router_binding_obj_exist(context, binding,
|
if not router_binding_obj_exist(context, binding,
|
||||||
net_ids, rtr_ids, plr_tlr_ids):
|
net_ids, rtr_ids, plr_tlr_ids):
|
||||||
orphaned_list.append(binding)
|
orphaned_list.append(binding)
|
||||||
@ -214,18 +209,6 @@ def router_binding_obj_exist(context, binding, net_ids, rtr_ids, plr_tlr_ids):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
def get_orphaned_edges():
|
|
||||||
nsxv_edge_ids = set()
|
|
||||||
for edge in utils.get_nsxv_backend_edges():
|
|
||||||
nsxv_edge_ids.add(edge.get('id'))
|
|
||||||
|
|
||||||
neutron_edge_bindings = set()
|
|
||||||
for binding in get_router_edge_bindings():
|
|
||||||
neutron_edge_bindings.add(binding.edge_id)
|
|
||||||
|
|
||||||
return nsxv_edge_ids - neutron_edge_bindings
|
|
||||||
|
|
||||||
|
|
||||||
@admin_utils.output_header
|
@admin_utils.output_header
|
||||||
def nsx_list_orphaned_edges(resource, event, trigger, **kwargs):
|
def nsx_list_orphaned_edges(resource, event, trigger, **kwargs):
|
||||||
"""List orphaned Edges on NSXv.
|
"""List orphaned Edges on NSXv.
|
||||||
@ -235,7 +218,7 @@ def nsx_list_orphaned_edges(resource, event, trigger, **kwargs):
|
|||||||
"""
|
"""
|
||||||
LOG.info("NSXv edges present on NSXv backend but not present "
|
LOG.info("NSXv edges present on NSXv backend but not present "
|
||||||
"in Neutron DB\n")
|
"in Neutron DB\n")
|
||||||
orphaned_edges = get_orphaned_edges()
|
orphaned_edges = utils.get_orphaned_edges()
|
||||||
if not orphaned_edges:
|
if not orphaned_edges:
|
||||||
LOG.info("\nNo orphaned edges found."
|
LOG.info("\nNo orphaned edges found."
|
||||||
"\nNeutron DB and NSXv backend are in sync\n")
|
"\nNeutron DB and NSXv backend are in sync\n")
|
||||||
@ -250,7 +233,7 @@ def nsx_list_orphaned_edges(resource, event, trigger, **kwargs):
|
|||||||
@admin_utils.output_header
|
@admin_utils.output_header
|
||||||
def nsx_delete_orphaned_edges(resource, event, trigger, **kwargs):
|
def nsx_delete_orphaned_edges(resource, event, trigger, **kwargs):
|
||||||
"""Delete orphaned edges from NSXv backend"""
|
"""Delete orphaned edges from NSXv backend"""
|
||||||
orphaned_edges = get_orphaned_edges()
|
orphaned_edges = utils.get_orphaned_edges()
|
||||||
LOG.info("Before delete; Orphaned Edges: %s", orphaned_edges)
|
LOG.info("Before delete; Orphaned Edges: %s", orphaned_edges)
|
||||||
|
|
||||||
if not kwargs.get('force'):
|
if not kwargs.get('force'):
|
||||||
@ -268,7 +251,7 @@ def nsx_delete_orphaned_edges(resource, event, trigger, **kwargs):
|
|||||||
nsxv_c.delete_edge(edge)
|
nsxv_c.delete_edge(edge)
|
||||||
|
|
||||||
LOG.info("After delete; Orphaned Edges: \n%s",
|
LOG.info("After delete; Orphaned Edges: \n%s",
|
||||||
pprint.pformat(get_orphaned_edges()))
|
pprint.pformat(utils.get_orphaned_edges()))
|
||||||
|
|
||||||
|
|
||||||
def get_missing_edges():
|
def get_missing_edges():
|
||||||
@ -277,7 +260,7 @@ def get_missing_edges():
|
|||||||
nsxv_edge_ids.add(edge.get('id'))
|
nsxv_edge_ids.add(edge.get('id'))
|
||||||
|
|
||||||
neutron_edge_bindings = set()
|
neutron_edge_bindings = set()
|
||||||
for binding in get_router_edge_bindings():
|
for binding in utils.get_router_edge_bindings():
|
||||||
neutron_edge_bindings.add(binding.edge_id)
|
neutron_edge_bindings.add(binding.edge_id)
|
||||||
|
|
||||||
return neutron_edge_bindings - nsxv_edge_ids
|
return neutron_edge_bindings - nsxv_edge_ids
|
||||||
|
@ -31,6 +31,7 @@ from neutron_lib import constants as nl_constants
|
|||||||
from neutron_lib import context as n_context
|
from neutron_lib import context as n_context
|
||||||
|
|
||||||
from vmware_nsx.common import config
|
from vmware_nsx.common import config
|
||||||
|
from vmware_nsx.common import exceptions as nsx_exc
|
||||||
from vmware_nsx.common import nsxv_constants
|
from vmware_nsx.common import nsxv_constants
|
||||||
from vmware_nsx.common import utils as c_utils
|
from vmware_nsx.common import utils as c_utils
|
||||||
from vmware_nsx.db import nsx_portbindings_db as portbinding
|
from vmware_nsx.db import nsx_portbindings_db as portbinding
|
||||||
@ -69,7 +70,7 @@ n_warnings = 0
|
|||||||
def log_error(msg):
|
def log_error(msg):
|
||||||
global all_errors
|
global all_errors
|
||||||
global n_errors
|
global n_errors
|
||||||
LOG.error(msg)
|
LOG.info("ERROR: %s", msg)
|
||||||
all_errors.append(msg)
|
all_errors.append(msg)
|
||||||
n_errors = n_errors + 1
|
n_errors = n_errors + 1
|
||||||
|
|
||||||
@ -77,11 +78,403 @@ def log_error(msg):
|
|||||||
def log_warning(msg):
|
def log_warning(msg):
|
||||||
global all_warnings
|
global all_warnings
|
||||||
global n_warnings
|
global n_warnings
|
||||||
LOG.warning(msg)
|
LOG.info("WARNING: %s", msg)
|
||||||
all_warnings.append(msg)
|
all_warnings.append(msg)
|
||||||
n_warnings = n_warnings + 1
|
n_warnings = n_warnings + 1
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_ports(plugin, admin_context):
|
||||||
|
# Ports validations:
|
||||||
|
# Max number of allowed address pairs (allowing 1 for fixed ips)
|
||||||
|
num_allowed_addr_pairs = nsxlib_consts.NUM_ALLOWED_IP_ADDRESSES_v4 - 1
|
||||||
|
ports = plugin.get_ports(admin_context)
|
||||||
|
for port in ports:
|
||||||
|
net_id = port['network_id']
|
||||||
|
# Too many address pairs in a port
|
||||||
|
address_pairs = port.get(addr_apidef.ADDRESS_PAIRS, [])
|
||||||
|
if len(address_pairs) > num_allowed_addr_pairs:
|
||||||
|
log_warning("%s allowed address pairs for port %s. "
|
||||||
|
"Only %s are allowed." %
|
||||||
|
(len(address_pairs), port['id'],
|
||||||
|
num_allowed_addr_pairs))
|
||||||
|
|
||||||
|
fixed_ips = [fixed.get('ip_address')
|
||||||
|
for fixed in port['fixed_ips']]
|
||||||
|
for pair in address_pairs:
|
||||||
|
if (port['mac_address'] == pair['mac_address'] and
|
||||||
|
pair['ip_address'] in fixed_ips):
|
||||||
|
log_error("Port %s address pair cannot be "
|
||||||
|
"identical to the fixed ip." % port['id'])
|
||||||
|
|
||||||
|
# Compute port on external network
|
||||||
|
if (port.get('device_owner', '').startswith(
|
||||||
|
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX) and
|
||||||
|
plugin._network_is_external(admin_context, net_id)):
|
||||||
|
log_error("Compute port %s on external network %s is "
|
||||||
|
"not allowed." % (port['id'], net_id))
|
||||||
|
|
||||||
|
# direct vnic ports are allowed only with vlan networks
|
||||||
|
vnic = port.get(pbin.VNIC_TYPE)
|
||||||
|
if vnic in portbinding.VNIC_TYPES_DIRECT_PASSTHROUGH:
|
||||||
|
net = plugin.get_network(admin_context, port['network_id'])
|
||||||
|
net_type = net.get(pnet.NETWORK_TYPE)
|
||||||
|
if net_type != 'vlan':
|
||||||
|
log_error("Port %s vnic type %s is not supported "
|
||||||
|
"with network type %s." % (port['id'],
|
||||||
|
vnic, net_type))
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_networks(plugin, admin_context, transit_networks):
|
||||||
|
# Networks & subnets validations:
|
||||||
|
networks = plugin.get_networks(admin_context)
|
||||||
|
for net in networks:
|
||||||
|
# Skip internal networks
|
||||||
|
if net['project_id'] == nsxv_constants.INTERNAL_TENANT_ID:
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Skip public networks
|
||||||
|
if plugin._network_is_external(admin_context, net['id']):
|
||||||
|
continue
|
||||||
|
|
||||||
|
# VXLAN or portgroup provider networks
|
||||||
|
net_type = net.get(pnet.NETWORK_TYPE)
|
||||||
|
overlay_net = bool(net_type != c_utils.NsxVNetworkTypes.VLAN)
|
||||||
|
if (net_type == c_utils.NsxVNetworkTypes.VXLAN or
|
||||||
|
net_type == c_utils.NsxVNetworkTypes.PORTGROUP):
|
||||||
|
log_error("Network %s of type %s is not supported." %
|
||||||
|
(net['id'], net_type))
|
||||||
|
|
||||||
|
subnets = plugin._get_subnets_by_network(admin_context, net['id'])
|
||||||
|
n_dhcp_subnets = 0
|
||||||
|
|
||||||
|
# Multiple DHCP subnets per network
|
||||||
|
for subnet in subnets:
|
||||||
|
if subnet['enable_dhcp']:
|
||||||
|
n_dhcp_subnets = n_dhcp_subnets + 1
|
||||||
|
if n_dhcp_subnets > 1:
|
||||||
|
log_error("Network %s has %s dhcp subnets. Only 1 is "
|
||||||
|
"allowed." % (net['id'], n_dhcp_subnets))
|
||||||
|
|
||||||
|
# Network attached to multiple routers
|
||||||
|
intf_ports = plugin._get_network_interface_ports(
|
||||||
|
admin_context, net['id'])
|
||||||
|
if len(intf_ports) > 1:
|
||||||
|
log_error("Network %s has interfaces on multiple "
|
||||||
|
"routers. Only 1 is allowed." % net['id'])
|
||||||
|
|
||||||
|
if (cfg.CONF.vlan_transparent and
|
||||||
|
net.get('vlan_transparent') is True):
|
||||||
|
if len(intf_ports) > 0:
|
||||||
|
log_error("VLAN Transparent network %s cannot be "
|
||||||
|
"attached to a logical router." % net['id'])
|
||||||
|
if n_dhcp_subnets > 0:
|
||||||
|
log_error("DHCP is not supported for VLAN "
|
||||||
|
"transparent network %s." % net['id'])
|
||||||
|
|
||||||
|
# Subnets overlapping with the transit network
|
||||||
|
ipv6_subnets = 0
|
||||||
|
for subnet in subnets:
|
||||||
|
# get the subnet IPs
|
||||||
|
if ('allocation_pools' in subnet and
|
||||||
|
validators.is_attr_set(subnet['allocation_pools'])):
|
||||||
|
# use the pools instead of the cidr
|
||||||
|
subnet_networks = [
|
||||||
|
netaddr.IPRange(pool.get('start'), pool.get('end'))
|
||||||
|
for pool in subnet.get('allocation_pools')]
|
||||||
|
else:
|
||||||
|
cidr = subnet.get('cidr')
|
||||||
|
if not validators.is_attr_set(cidr):
|
||||||
|
return
|
||||||
|
subnet_networks = [netaddr.IPNetwork(subnet['cidr'])]
|
||||||
|
|
||||||
|
for subnet_net in subnet_networks:
|
||||||
|
if (netaddr.IPSet(subnet_net) &
|
||||||
|
netaddr.IPSet(transit_networks)):
|
||||||
|
log_error("Subnet %s overlaps with the transit "
|
||||||
|
"network ips: %s." %
|
||||||
|
(subnet['id'], transit_networks))
|
||||||
|
|
||||||
|
# Cannot support non-dhcp overlay subnet attached to a router
|
||||||
|
# if there is also a dhcp subnet on the same network
|
||||||
|
if (overlay_net and n_dhcp_subnets > 0 and
|
||||||
|
not subnet['enable_dhcp']):
|
||||||
|
# look for a router interface for this subnet
|
||||||
|
for if_port in intf_ports:
|
||||||
|
if if_port['fixed_ips']:
|
||||||
|
if_sub = if_port['fixed_ips'][0]['subnet_id']
|
||||||
|
if subnet['id'] == if_sub:
|
||||||
|
log_error("Network %s has non-dhcp "
|
||||||
|
"subnet attached to a router, and "
|
||||||
|
"another dhcp subnet. This is not "
|
||||||
|
"allowed." % net['id'])
|
||||||
|
|
||||||
|
# Cannot use a non-gateway subnet attached to a router
|
||||||
|
if not subnet['gateway_ip']:
|
||||||
|
for if_port in intf_ports:
|
||||||
|
if if_port['fixed_ips']:
|
||||||
|
if_sub = if_port['fixed_ips'][0]['subnet_id']
|
||||||
|
if subnet['id'] == if_sub:
|
||||||
|
log_error("Subnet %s attached to a "
|
||||||
|
"router must have a gateway IP." %
|
||||||
|
subnet['id'])
|
||||||
|
else:
|
||||||
|
# The gateway ip must belong to the subnet
|
||||||
|
gw_ip = netaddr.IPAddress(subnet['gateway_ip'])
|
||||||
|
cidr = netaddr.IPNetwork(subnet['cidr'])
|
||||||
|
if gw_ip.version != cidr.version:
|
||||||
|
log_error("Subnet %s gateway ip version %s "
|
||||||
|
"does not match subnet cidr." %
|
||||||
|
(subnet['id'], gw_ip.version))
|
||||||
|
if gw_ip not in cidr:
|
||||||
|
log_error("Subnet %s gateway ip %s does not belong to "
|
||||||
|
"subnet cidr %s" %
|
||||||
|
(subnet['id'], subnet['gateway_ip'],
|
||||||
|
subnet['cidr']))
|
||||||
|
|
||||||
|
# only 2 dns_nameservers allowed
|
||||||
|
if len(subnet.get('dns_nameservers', [])) > 2:
|
||||||
|
log_error("Subnet %s cannot have more than 2 "
|
||||||
|
"dns_nameservers." % subnet['id'])
|
||||||
|
|
||||||
|
if subnet.get('ip_version') == 6:
|
||||||
|
ipv6_subnets = ipv6_subnets + 1
|
||||||
|
|
||||||
|
if ipv6_subnets > 1:
|
||||||
|
log_error("Network %s cannot have more than 1 "
|
||||||
|
"IPv6 subnets." % net['id'])
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_routers(plugin, admin_context):
|
||||||
|
# Routers validations:
|
||||||
|
routers = plugin.get_routers(admin_context)
|
||||||
|
for router in routers:
|
||||||
|
# Interface subnets overlap with the GW subnet
|
||||||
|
gw_subnets = plugin._find_router_gw_subnets(admin_context, router)
|
||||||
|
gw_cidrs = [subnet['cidr'] for subnet in gw_subnets]
|
||||||
|
gw_ip_set = netaddr.IPSet(gw_cidrs)
|
||||||
|
|
||||||
|
if_cidrs = plugin._find_router_subnets_cidrs(
|
||||||
|
admin_context, router['id'])
|
||||||
|
if_ip_set = netaddr.IPSet(if_cidrs)
|
||||||
|
|
||||||
|
if gw_ip_set & if_ip_set:
|
||||||
|
log_error("Interface network of router %s cannot "
|
||||||
|
"overlap with router GW network" % router['id'])
|
||||||
|
|
||||||
|
# router without external gw cannot be attached to a vlan subnet
|
||||||
|
router_db = plugin._get_router(admin_context, router['id'])
|
||||||
|
if not router_db.gw_port:
|
||||||
|
router_subnets = plugin._load_router_subnet_cidrs_from_db(
|
||||||
|
admin_context, router['id'])
|
||||||
|
for subnet in router_subnets:
|
||||||
|
net_id = subnet['network_id']
|
||||||
|
net = plugin.get_network(admin_context, net_id)
|
||||||
|
net_type = net.get(pnet.NETWORK_TYPE)
|
||||||
|
if net_type == c_utils.NsxVNetworkTypes.VLAN:
|
||||||
|
log_error("Vlan network %s cannot be attached "
|
||||||
|
"to router %s without a gateway" % (net_id,
|
||||||
|
router['id']))
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_loadbalancers(plugin, admin_context):
|
||||||
|
# Octavia loadbalancers validation:
|
||||||
|
filters = {'device_owner': [nl_constants.DEVICE_OWNER_LOADBALANCERV2,
|
||||||
|
oct_const.DEVICE_OWNER_OCTAVIA]}
|
||||||
|
lbs_map = {}
|
||||||
|
lb_ports = plugin.get_ports(admin_context, filters=filters)
|
||||||
|
for port in lb_ports:
|
||||||
|
lb_id = port.get('device_id')
|
||||||
|
fixed_ips = port.get('fixed_ips', [])
|
||||||
|
if fixed_ips:
|
||||||
|
subnet_id = fixed_ips[0]['subnet_id']
|
||||||
|
network = lb_utils.get_network_from_subnet(
|
||||||
|
admin_context, plugin, subnet_id)
|
||||||
|
lb_rtr_id = _get_router_from_network(
|
||||||
|
admin_context, plugin, subnet_id)
|
||||||
|
# only 20 loadbalancers are allowed on the same router
|
||||||
|
if lb_rtr_id not in lbs_map:
|
||||||
|
lbs_map[lb_rtr_id] = 1
|
||||||
|
else:
|
||||||
|
lbs_map[lb_rtr_id] = lbs_map[lb_rtr_id] + 1
|
||||||
|
if lbs_map[lb_rtr_id] == lb_pol.SERVICE_LB_TAG_MAX + 1:
|
||||||
|
log_error("Router %s has over %s attached "
|
||||||
|
"loadbalancers. This is not supported." %
|
||||||
|
(lb_rtr_id, lb_pol.SERVICE_LB_TAG_MAX))
|
||||||
|
# Loadbalancer vip subnet must be connected to a router or
|
||||||
|
# belong to an external network
|
||||||
|
if (not lb_rtr_id and network and
|
||||||
|
not network.get('router:external')):
|
||||||
|
log_error("Loadbalancer %s subnet %s is not "
|
||||||
|
"external nor connected to a router." %
|
||||||
|
(port.get('device_id'), subnet_id))
|
||||||
|
|
||||||
|
if not lb_id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
lb_id = lb_id[3:]
|
||||||
|
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
||||||
|
admin_context.session, lb_id)
|
||||||
|
if not lb_binding or not lb_binding['edge_id']:
|
||||||
|
LOG.info("Cannot find edge for Loadbalancer %s", lb_id)
|
||||||
|
continue
|
||||||
|
edge_id = lb_binding['edge_id']
|
||||||
|
|
||||||
|
# Multiple listeners on the same pool is not supported
|
||||||
|
result = plugin.nsx_v.vcns.get_vips(edge_id)
|
||||||
|
if len(result) == 2:
|
||||||
|
edge_vs = result[1]
|
||||||
|
pools = []
|
||||||
|
for vip in edge_vs.get('virtualServer', []):
|
||||||
|
if not vip.get('defaultPoolId'):
|
||||||
|
continue
|
||||||
|
if vip['defaultPoolId'] in pools:
|
||||||
|
log_error("Found multiple listeners using the "
|
||||||
|
"same default pool with loadbalancer %s. "
|
||||||
|
"This is not supported." % lb_id)
|
||||||
|
break
|
||||||
|
pools.append(vip['defaultPoolId'])
|
||||||
|
|
||||||
|
# Cannot support LB with members from various subnets not uplinked
|
||||||
|
# to the same edge router. This can be indicated by multiple
|
||||||
|
# internal interfaces on the LB edge
|
||||||
|
is_old_lb = lb_common.is_lb_on_router_edge(
|
||||||
|
admin_context, plugin, edge_id)
|
||||||
|
if not is_old_lb:
|
||||||
|
filters = {'device_id': [lb_id],
|
||||||
|
'device_owner': [lb_common.LBAAS_DEVICE_OWNER]}
|
||||||
|
lb_ports = plugin.get_ports(admin_context, filters=filters)
|
||||||
|
# get the subnets of those ports
|
||||||
|
lb_subnets = list(set([port['fixed_ips'][0]['subnet_id']
|
||||||
|
for port in lb_ports]))
|
||||||
|
# make sure all subnets are connected to the same router
|
||||||
|
lb_routers = [lb_rtr_id]
|
||||||
|
for sub_id in lb_subnets:
|
||||||
|
router_id = _get_router_from_network(
|
||||||
|
admin_context, plugin, sub_id)
|
||||||
|
if not router_id:
|
||||||
|
log_error("Found member of subnet %s not "
|
||||||
|
"uplinked to any router on loadbalancer "
|
||||||
|
"%s. This is not supported." %
|
||||||
|
(sub_id, lb_id))
|
||||||
|
elif router_id not in lb_routers:
|
||||||
|
lb_routers.append(router_id)
|
||||||
|
if len(lb_routers) > 1:
|
||||||
|
log_error("Found members/vips from different "
|
||||||
|
"subnets or uplinks to different routers on "
|
||||||
|
"loadbalancer %s. This is not supported." %
|
||||||
|
lb_id)
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_security_groups(plugin, admin_context):
|
||||||
|
# Security groups without policies
|
||||||
|
sgs = plugin.get_security_groups(admin_context)
|
||||||
|
for sg in sgs:
|
||||||
|
if plugin._is_policy_security_group(admin_context, sg['id']):
|
||||||
|
log_error("Security group %s has NSX policy. This is not "
|
||||||
|
"supported." % sg['id'])
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_non_neutron_networks(admin_context):
|
||||||
|
# Look for orphaned neutron networks and non neutron backend networks
|
||||||
|
backend_networks = utils.get_networks()
|
||||||
|
missing_networks = utils.get_orphaned_networks(backend_networks)
|
||||||
|
for net in missing_networks:
|
||||||
|
log_warning("NSX backend network %s:%s is missing from Neutron "
|
||||||
|
"and is probably an orphaned. Please delete it." %
|
||||||
|
(net.get('moref'), net.get('name')))
|
||||||
|
|
||||||
|
for net in backend_networks:
|
||||||
|
moref = net['moref']
|
||||||
|
name = net['name']
|
||||||
|
net_type = net['type']
|
||||||
|
|
||||||
|
if ((len(name) < 36 or not uuidutils.is_uuid_like(name)) and
|
||||||
|
net_type in ['DistributedVirtualPortgroup', 'VirtualWire']):
|
||||||
|
if (net_type == 'DistributedVirtualPortgroup' and
|
||||||
|
name.startswith('edge-')):
|
||||||
|
continue
|
||||||
|
if (name == 'DPortGroup' and net_type ==
|
||||||
|
'DistributedVirtualPortgroup'):
|
||||||
|
continue
|
||||||
|
|
||||||
|
if name:
|
||||||
|
# Find the vlan networks
|
||||||
|
id_from_name = name[-36:]
|
||||||
|
if nsxv_db.get_network_bindings(admin_context.session,
|
||||||
|
id_from_name):
|
||||||
|
continue
|
||||||
|
if net_type == 'DistributedVirtualPortgroup':
|
||||||
|
if nsxv_db.get_network_bindings_by_physical_net(
|
||||||
|
admin_context.session, moref):
|
||||||
|
continue
|
||||||
|
if net_type == 'VirtualWire':
|
||||||
|
# Find internal networks for distributed routers
|
||||||
|
filters = {'lswitch_id': moref}
|
||||||
|
if nsxv_db.get_nsxv_router_bindings(admin_context.session,
|
||||||
|
like_filters=filters):
|
||||||
|
continue
|
||||||
|
|
||||||
|
log_warning("NSX backend network %s:%s is not a "
|
||||||
|
"Neutron network and cannot be migrated. "
|
||||||
|
"Please delete it or migrate it manually." %
|
||||||
|
(moref, name))
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_non_neutron_edges():
|
||||||
|
# Look for orphaned or non-neutron edges
|
||||||
|
orphaned_edges = utils.get_orphaned_edges_data()
|
||||||
|
for edge in orphaned_edges:
|
||||||
|
log_warning("NSX %s:%s does not belong to Neutron. "
|
||||||
|
"Please delete it." %
|
||||||
|
(edge.get('id'), edge.get('name')))
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_qos(admin_context):
|
||||||
|
# Validate QoS limits
|
||||||
|
qos_plugin_inst = qos_plugin.QoSPlugin()
|
||||||
|
policies = qos_plugin_inst.get_policies(admin_context)
|
||||||
|
for policy in policies:
|
||||||
|
for rule in policy.get('rules', []):
|
||||||
|
if rule.get('type') == 'bandwidth_limit':
|
||||||
|
# Validate the limits
|
||||||
|
if rule.get('max_kbps') < qos_utils.MAX_KBPS_MIN_VALUE:
|
||||||
|
log_error("QoS Policy %s has max_kbps below the "
|
||||||
|
"minimal value of %s. This is not supported." %
|
||||||
|
(policy['id'], rule['max_kbps']))
|
||||||
|
if rule.get('max_burst_kbps') > qos_utils.MAX_BURST_MAX_VALUE:
|
||||||
|
log_error("QoS Policy %s has max_burst_kbps above "
|
||||||
|
"the maximal value of %s. This is not "
|
||||||
|
"supported." %
|
||||||
|
(policy['id'], rule['max_burst_kbps']))
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_l2gw(admin_context):
|
||||||
|
# L2GW is not supported with the policy plugin
|
||||||
|
try:
|
||||||
|
l2gws = admin_context.session.query(l2gateway_models.L2Gateway).all()
|
||||||
|
except Exception:
|
||||||
|
# L2GW DB was not initialized
|
||||||
|
pass
|
||||||
|
else:
|
||||||
|
if len(l2gws):
|
||||||
|
log_error("Found %s L2Gws: %s. Networking-l2gw is not "
|
||||||
|
"supported." % (len(l2gws), [l2gw.id for l2gw in l2gws]))
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_config():
|
||||||
|
# General config options / per AZ which are unsupported
|
||||||
|
config.register_nsxv_azs(cfg.CONF, cfg.CONF.nsxv.availability_zones)
|
||||||
|
zones = nsx_az.NsxVAvailabilityZones()
|
||||||
|
unsupported_configs = ['edge_ha', 'edge_host_groups']
|
||||||
|
for az in zones.list_availability_zones_objects():
|
||||||
|
for attr in unsupported_configs:
|
||||||
|
if getattr(az, attr):
|
||||||
|
log_warning("\'%s\' configuration is not supported "
|
||||||
|
"and will not be honored by NSX-T (availability "
|
||||||
|
"zone %s)" % (attr, az.name))
|
||||||
|
|
||||||
|
|
||||||
@admin_utils.output_header
|
@admin_utils.output_header
|
||||||
def validate_config_for_migration(resource, event, trigger, **kwargs):
|
def validate_config_for_migration(resource, event, trigger, **kwargs):
|
||||||
"""Validate the nsxv configuration before migration to nsx-t"""
|
"""Validate the nsxv configuration before migration to nsx-t"""
|
||||||
@ -113,372 +506,42 @@ def validate_config_for_migration(resource, event, trigger, **kwargs):
|
|||||||
|
|
||||||
admin_context = n_context.get_admin_context()
|
admin_context = n_context.get_admin_context()
|
||||||
|
|
||||||
# General config options / per AZ which are unsupported
|
_validate_config()
|
||||||
config.register_nsxv_azs(cfg.CONF, cfg.CONF.nsxv.availability_zones)
|
|
||||||
zones = nsx_az.NsxVAvailabilityZones()
|
|
||||||
unsupported_configs = ['edge_ha', 'edge_host_groups']
|
|
||||||
for az in zones.list_availability_zones_objects():
|
|
||||||
for attr in unsupported_configs:
|
|
||||||
if getattr(az, attr):
|
|
||||||
log_warning("WARNING: \'%s\' configuration is not supported "
|
|
||||||
"and will not be honored by NSX-T (availability "
|
|
||||||
"zone %s)" % (attr, az.name))
|
|
||||||
|
|
||||||
|
try:
|
||||||
with utils.NsxVPluginWrapper() as plugin:
|
with utils.NsxVPluginWrapper() as plugin:
|
||||||
# The migration is supported only for NSX 6.4.9 and above
|
# The migration is supported only for NSX 6.4.9 and above
|
||||||
nsx_ver = plugin.nsx_v.vcns.get_version()
|
nsx_ver = plugin.nsx_v.vcns.get_version()
|
||||||
if not c_utils.is_nsxv_version_6_4_9(nsx_ver):
|
if not c_utils.is_nsxv_version_6_4_9(nsx_ver):
|
||||||
log_error("ERROR: Migration with NSX-V version %s is not "
|
log_error("Migration with NSX-V version %s is not "
|
||||||
"supported." % nsx_ver)
|
"supported." % nsx_ver)
|
||||||
|
|
||||||
# Ports validations:
|
_validate_ports(plugin, admin_context)
|
||||||
# Max number of allowed address pairs (allowing 1 for fixed ips)
|
_validate_networks(plugin, admin_context, transit_networks)
|
||||||
num_allowed_addr_pairs = nsxlib_consts.NUM_ALLOWED_IP_ADDRESSES_v4 - 1
|
_validate_routers(plugin, admin_context)
|
||||||
ports = plugin.get_ports(admin_context)
|
_validate_loadbalancers(plugin, admin_context)
|
||||||
for port in ports:
|
_validate_security_groups(plugin, admin_context)
|
||||||
net_id = port['network_id']
|
|
||||||
# Too many address pairs in a port
|
|
||||||
address_pairs = port.get(addr_apidef.ADDRESS_PAIRS, [])
|
|
||||||
if len(address_pairs) > num_allowed_addr_pairs:
|
|
||||||
log_warning("WARNING: %s allowed address pairs for port %s. "
|
|
||||||
"Only %s are allowed." %
|
|
||||||
(len(address_pairs), port['id'],
|
|
||||||
num_allowed_addr_pairs))
|
|
||||||
|
|
||||||
fixed_ips = [fixed.get('ip_address')
|
except nsx_exc.NsxPluginException:
|
||||||
for fixed in port['fixed_ips']]
|
log_error("NSX-V configuration cannot be migrated because the "
|
||||||
for pair in address_pairs:
|
"plugin is currently down. This may be caused by a "
|
||||||
if (port['mac_address'] == pair['mac_address'] and
|
"connectivity issue with the NSX-v")
|
||||||
pair['ip_address'] in fixed_ips):
|
|
||||||
log_error("ERROR: Port %s address pair cannot be "
|
|
||||||
"identical to the fixed ip." % port['id'])
|
|
||||||
|
|
||||||
# Compute port on external network
|
|
||||||
if (port.get('device_owner', '').startswith(
|
|
||||||
nl_constants.DEVICE_OWNER_COMPUTE_PREFIX) and
|
|
||||||
plugin._network_is_external(admin_context, net_id)):
|
|
||||||
log_error("ERROR: Compute port %s on external network %s is "
|
|
||||||
"not allowed." % (port['id'], net_id))
|
|
||||||
|
|
||||||
vnic = port.get(pbin.VNIC_TYPE)
|
|
||||||
if vnic in portbinding.VNIC_TYPES_DIRECT_PASSTHROUGH:
|
|
||||||
net = plugin.get_network(admin_context, port['network_id'])
|
|
||||||
net_type = net.get(pnet.NETWORK_TYPE)
|
|
||||||
if net_type not in portbinding.SUPPORTED_T_NETWORK_TYPES:
|
|
||||||
log_error("ERROR: Port %s vnic type %s is not supported "
|
|
||||||
"with network type %s." % (port['id'],
|
|
||||||
vnic, net_type))
|
|
||||||
|
|
||||||
# Networks & subnets validations:
|
|
||||||
networks = plugin.get_networks(admin_context)
|
|
||||||
for net in networks:
|
|
||||||
# Skip internal networks
|
|
||||||
if net['project_id'] == nsxv_constants.INTERNAL_TENANT_ID:
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Skip public networks
|
|
||||||
if plugin._network_is_external(admin_context, net['id']):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# VXLAN or portgroup provider networks
|
|
||||||
net_type = net.get(pnet.NETWORK_TYPE)
|
|
||||||
overlay_net = bool(net_type != c_utils.NsxVNetworkTypes.VLAN)
|
|
||||||
if (net_type == c_utils.NsxVNetworkTypes.VXLAN or
|
|
||||||
net_type == c_utils.NsxVNetworkTypes.PORTGROUP):
|
|
||||||
log_error("ERROR: Network %s of type %s is not supported." %
|
|
||||||
(net['id'], net_type))
|
|
||||||
|
|
||||||
subnets = plugin._get_subnets_by_network(admin_context, net['id'])
|
|
||||||
n_dhcp_subnets = 0
|
|
||||||
|
|
||||||
# Multiple DHCP subnets per network
|
|
||||||
for subnet in subnets:
|
|
||||||
if subnet['enable_dhcp']:
|
|
||||||
n_dhcp_subnets = n_dhcp_subnets + 1
|
|
||||||
if n_dhcp_subnets > 1:
|
|
||||||
log_error("ERROR: Network %s has %s dhcp subnets. Only 1 is "
|
|
||||||
"allowed." % (net['id'], n_dhcp_subnets))
|
|
||||||
|
|
||||||
# Network attached to multiple routers
|
|
||||||
intf_ports = plugin._get_network_interface_ports(
|
|
||||||
admin_context, net['id'])
|
|
||||||
if len(intf_ports) > 1:
|
|
||||||
log_error("ERROR: Network %s has interfaces on multiple "
|
|
||||||
"routers. Only 1 is allowed." % net['id'])
|
|
||||||
|
|
||||||
if (cfg.CONF.vlan_transparent and
|
|
||||||
net.get('vlan_transparent') is True):
|
|
||||||
if len(intf_ports) > 0:
|
|
||||||
log_error("ERROR: VLAN Transparent network %s cannot be "
|
|
||||||
"attached to a logical router." % net['id'])
|
|
||||||
if n_dhcp_subnets > 0:
|
|
||||||
log_error("ERROR: DHCP is not supported for VLAN "
|
|
||||||
"transparent network %s." % net['id'])
|
|
||||||
|
|
||||||
# Subnets overlapping with the transit network
|
|
||||||
ipv6_subnets = 0
|
|
||||||
for subnet in subnets:
|
|
||||||
# get the subnet IPs
|
|
||||||
if ('allocation_pools' in subnet and
|
|
||||||
validators.is_attr_set(subnet['allocation_pools'])):
|
|
||||||
# use the pools instead of the cidr
|
|
||||||
subnet_networks = [
|
|
||||||
netaddr.IPRange(pool.get('start'), pool.get('end'))
|
|
||||||
for pool in subnet.get('allocation_pools')]
|
|
||||||
else:
|
else:
|
||||||
cidr = subnet.get('cidr')
|
_validate_non_neutron_networks(admin_context)
|
||||||
if not validators.is_attr_set(cidr):
|
_validate_non_neutron_edges()
|
||||||
return
|
_validate_qos(admin_context)
|
||||||
subnet_networks = [netaddr.IPNetwork(subnet['cidr'])]
|
_validate_l2gw(admin_context)
|
||||||
|
|
||||||
for subnet_net in subnet_networks:
|
|
||||||
if (netaddr.IPSet(subnet_net) &
|
|
||||||
netaddr.IPSet(transit_networks)):
|
|
||||||
log_error("ERROR: Subnet %s overlaps with the transit "
|
|
||||||
"network ips: %s." %
|
|
||||||
(subnet['id'], transit_networks))
|
|
||||||
|
|
||||||
# Cannot support non-dhcp overlay subnet attached to a router
|
|
||||||
# if there is also a dhcp subnet on the same network
|
|
||||||
if (overlay_net and n_dhcp_subnets > 0 and
|
|
||||||
not subnet['enable_dhcp']):
|
|
||||||
# look for a router interface for this subnet
|
|
||||||
for if_port in intf_ports:
|
|
||||||
if if_port['fixed_ips']:
|
|
||||||
if_sub = if_port['fixed_ips'][0]['subnet_id']
|
|
||||||
if subnet['id'] == if_sub:
|
|
||||||
log_error("ERROR: Network %s has non-dhcp "
|
|
||||||
"subnet attached to a router, and "
|
|
||||||
"another dhcp subnet. This is not "
|
|
||||||
"allowed." % net['id'])
|
|
||||||
|
|
||||||
# Cannot use a non-gateway subnet attached to a router
|
|
||||||
if not subnet['gateway_ip']:
|
|
||||||
for if_port in intf_ports:
|
|
||||||
if if_port['fixed_ips']:
|
|
||||||
if_sub = if_port['fixed_ips'][0]['subnet_id']
|
|
||||||
if subnet['id'] == if_sub:
|
|
||||||
log_error("ERROR: Subnet %s attached to a "
|
|
||||||
"router must have a gateway IP." %
|
|
||||||
subnet['id'])
|
|
||||||
# only 2 dns_nameservers allowed
|
|
||||||
if len(subnet.get('dns_nameservers', [])) > 2:
|
|
||||||
log_error("ERROR: Subnet %s cannot have more than 2 "
|
|
||||||
"dns_nameservers." % subnet['id'])
|
|
||||||
|
|
||||||
if subnet.get('ip_version') == 6:
|
|
||||||
ipv6_subnets = ipv6_subnets + 1
|
|
||||||
|
|
||||||
if ipv6_subnets > 1:
|
|
||||||
log_error("ERROR: Network %s cannot have more than 1 "
|
|
||||||
"IPv6 subnets." % net['id'])
|
|
||||||
|
|
||||||
# Routers validations:
|
|
||||||
routers = plugin.get_routers(admin_context)
|
|
||||||
for router in routers:
|
|
||||||
# Interface subnets overlap with the GW subnet
|
|
||||||
gw_subnets = plugin._find_router_gw_subnets(admin_context, router)
|
|
||||||
gw_cidrs = [subnet['cidr'] for subnet in gw_subnets]
|
|
||||||
gw_ip_set = netaddr.IPSet(gw_cidrs)
|
|
||||||
|
|
||||||
if_cidrs = plugin._find_router_subnets_cidrs(
|
|
||||||
admin_context, router['id'])
|
|
||||||
if_ip_set = netaddr.IPSet(if_cidrs)
|
|
||||||
|
|
||||||
if gw_ip_set & if_ip_set:
|
|
||||||
log_error("ERROR: Interface network of router %s cannot "
|
|
||||||
"overlap with router GW network" % router['id'])
|
|
||||||
|
|
||||||
# router without external gw cannot be attached to a vlan subnet
|
|
||||||
router_db = plugin._get_router(admin_context, router['id'])
|
|
||||||
if not router_db.gw_port:
|
|
||||||
router_subnets = plugin._load_router_subnet_cidrs_from_db(
|
|
||||||
admin_context, router['id'])
|
|
||||||
for subnet in router_subnets:
|
|
||||||
net_id = subnet['network_id']
|
|
||||||
net = plugin.get_network(admin_context, net_id)
|
|
||||||
net_type = net.get(pnet.NETWORK_TYPE)
|
|
||||||
if net_type == c_utils.NsxVNetworkTypes.VLAN:
|
|
||||||
log_error("ERROR: Vlan network %s cannot be attached "
|
|
||||||
"to router %s without a gateway" % (net_id,
|
|
||||||
router['id']))
|
|
||||||
|
|
||||||
# Look for orphaned neutron networks and non neutron backend networks
|
|
||||||
backend_networks = utils.get_networks()
|
|
||||||
missing_networks = utils.get_orphaned_networks(backend_networks)
|
|
||||||
for net in missing_networks:
|
|
||||||
log_warning("WARNING: NSX backend network %s:%s is missing from "
|
|
||||||
"neutron and is probably an orphaned. Please delete "
|
|
||||||
"it." % (net.get('moref'), net.get('name')))
|
|
||||||
|
|
||||||
for net in backend_networks:
|
|
||||||
moref = net['moref']
|
|
||||||
name = net['name']
|
|
||||||
net_type = net['type']
|
|
||||||
|
|
||||||
if ((len(name) < 36 or not uuidutils.is_uuid_like(name)) and
|
|
||||||
net_type in ['DistributedVirtualPortgroup', 'VirtualWire']):
|
|
||||||
if (net_type == 'DistributedVirtualPortgroup' and
|
|
||||||
name.startswith('edge-')):
|
|
||||||
continue
|
|
||||||
if (name == 'DPortGroup' and net_type ==
|
|
||||||
'DistributedVirtualPortgroup'):
|
|
||||||
continue
|
|
||||||
|
|
||||||
if name:
|
|
||||||
# Find the vlan networks
|
|
||||||
id_from_name = name[-36:]
|
|
||||||
if nsxv_db.get_network_bindings(admin_context.session,
|
|
||||||
id_from_name):
|
|
||||||
continue
|
|
||||||
if net_type == 'DistributedVirtualPortgroup':
|
|
||||||
if nsxv_db.get_network_bindings_by_physical_net(
|
|
||||||
admin_context.session, moref):
|
|
||||||
continue
|
|
||||||
if net_type == 'VirtualWire':
|
|
||||||
# Find internal networks for distributed routers
|
|
||||||
filters = {'lswitch_id': moref}
|
|
||||||
if nsxv_db.get_nsxv_router_bindings(admin_context.session,
|
|
||||||
like_filters=filters):
|
|
||||||
continue
|
|
||||||
|
|
||||||
log_warning("WARNING: NSX backend network %s:%s is not a "
|
|
||||||
"neutron network and cannot be migrated. "
|
|
||||||
"Please delete it or migrate it manually." %
|
|
||||||
(moref, name))
|
|
||||||
|
|
||||||
# Octavia loadbalancers validation:
|
|
||||||
filters = {'device_owner': [nl_constants.DEVICE_OWNER_LOADBALANCERV2,
|
|
||||||
oct_const.DEVICE_OWNER_OCTAVIA]}
|
|
||||||
lbs_map = {}
|
|
||||||
lb_ports = plugin.get_ports(admin_context, filters=filters)
|
|
||||||
for port in lb_ports:
|
|
||||||
lb_id = port.get('device_id')
|
|
||||||
fixed_ips = port.get('fixed_ips', [])
|
|
||||||
if fixed_ips:
|
|
||||||
subnet_id = fixed_ips[0]['subnet_id']
|
|
||||||
network = lb_utils.get_network_from_subnet(
|
|
||||||
admin_context, plugin, subnet_id)
|
|
||||||
lb_rtr_id = _get_router_from_network(
|
|
||||||
admin_context, plugin, subnet_id)
|
|
||||||
# only 20 loadbalancers are allowed on the same router
|
|
||||||
if lb_rtr_id not in lbs_map:
|
|
||||||
lbs_map[lb_rtr_id] = 1
|
|
||||||
else:
|
|
||||||
lbs_map[lb_rtr_id] = lbs_map[lb_rtr_id] + 1
|
|
||||||
if lbs_map[lb_rtr_id] == lb_pol.SERVICE_LB_TAG_MAX + 1:
|
|
||||||
log_error("ERROR: Router %s has over %s attached "
|
|
||||||
"loadbalancers. This is not supported." %
|
|
||||||
(lb_rtr_id, lb_pol.SERVICE_LB_TAG_MAX))
|
|
||||||
# Loadbalancer vip subnet must be connected to a router or
|
|
||||||
# belong to an external network
|
|
||||||
if (not lb_rtr_id and network and
|
|
||||||
not network.get('router:external')):
|
|
||||||
log_error("ERROR: Loadbalancer %s subnet %s is not "
|
|
||||||
"external nor connected to a router." %
|
|
||||||
(port.get('device_id'), subnet_id))
|
|
||||||
|
|
||||||
if not lb_id:
|
|
||||||
continue
|
|
||||||
|
|
||||||
lb_id = lb_id[3:]
|
|
||||||
lb_binding = nsxv_db.get_nsxv_lbaas_loadbalancer_binding(
|
|
||||||
admin_context.session, lb_id)
|
|
||||||
if not lb_binding or not lb_binding['edge_id']:
|
|
||||||
LOG.warning("Cannot find edge for Loadbalancer %s", lb_id)
|
|
||||||
continue
|
|
||||||
edge_id = lb_binding['edge_id']
|
|
||||||
|
|
||||||
# Multiple listeners on the same pool is not supported
|
|
||||||
result = plugin.nsx_v.vcns.get_vips(edge_id)
|
|
||||||
if len(result) == 2:
|
|
||||||
edge_vs = result[1]
|
|
||||||
pools = []
|
|
||||||
for vip in edge_vs.get('virtualServer', []):
|
|
||||||
if not vip.get('defaultPoolId'):
|
|
||||||
continue
|
|
||||||
if vip['defaultPoolId'] in pools:
|
|
||||||
log_error("ERROR: Found multiple listeners using the "
|
|
||||||
"same default pool with loadbalancer %s. "
|
|
||||||
"This is not supported." % lb_id)
|
|
||||||
break
|
|
||||||
pools.append(vip['defaultPoolId'])
|
|
||||||
|
|
||||||
# Cannot support LB with members from various subnets not uplinked
|
|
||||||
# to the same edge router. This can be indicated by multiple
|
|
||||||
# internal interfaces on the LB edge
|
|
||||||
is_old_lb = lb_common.is_lb_on_router_edge(
|
|
||||||
admin_context, plugin, edge_id)
|
|
||||||
if not is_old_lb:
|
|
||||||
filters = {'device_id': [lb_id],
|
|
||||||
'device_owner': [lb_common.LBAAS_DEVICE_OWNER]}
|
|
||||||
lb_ports = plugin.get_ports(admin_context, filters=filters)
|
|
||||||
# get the subnets of those ports
|
|
||||||
lb_subnets = list(set([port['fixed_ips'][0]['subnet_id']
|
|
||||||
for port in lb_ports]))
|
|
||||||
# make sure all subnets are connected to the same router
|
|
||||||
lb_routers = [lb_rtr_id]
|
|
||||||
for sub_id in lb_subnets:
|
|
||||||
router_id = _get_router_from_network(
|
|
||||||
admin_context, plugin, sub_id)
|
|
||||||
if not router_id:
|
|
||||||
log_error("ERROR: Found member of subnet %s not "
|
|
||||||
"uplinked to any router on loadbalancer "
|
|
||||||
"%s. This is not supported." %
|
|
||||||
(sub_id, lb_id))
|
|
||||||
elif router_id not in lb_routers:
|
|
||||||
lb_routers.append(router_id)
|
|
||||||
if len(lb_routers) > 1:
|
|
||||||
log_error("ERROR: Found members/vips from different "
|
|
||||||
"subnets or uplinks to different routers on "
|
|
||||||
"loadbalancer %s. This is not supported." %
|
|
||||||
lb_id)
|
|
||||||
break
|
|
||||||
|
|
||||||
# Security groups without policies
|
|
||||||
sgs = plugin.get_security_groups(admin_context)
|
|
||||||
for sg in sgs:
|
|
||||||
if plugin._is_policy_security_group(admin_context, sg['id']):
|
|
||||||
log_error("ERROR: Security group %s has NSX policy. This is not "
|
|
||||||
"supported." % sg['id'])
|
|
||||||
|
|
||||||
# Validate QoS limits
|
|
||||||
qos_plugin_inst = qos_plugin.QoSPlugin()
|
|
||||||
policies = qos_plugin_inst.get_policies(admin_context)
|
|
||||||
for policy in policies:
|
|
||||||
for rule in policy.get('rules', []):
|
|
||||||
if rule.get('type') == 'bandwidth_limit':
|
|
||||||
# Validate the limits
|
|
||||||
if rule.get('max_kbps') < qos_utils.MAX_KBPS_MIN_VALUE:
|
|
||||||
log_error("ERROR: QoS Policy %s has max_kbps below the "
|
|
||||||
"minimal value of %s. This is not supported." %
|
|
||||||
(policy['id'], rule['max_kbps']))
|
|
||||||
if rule.get('max_burst_kbps') > qos_utils.MAX_BURST_MAX_VALUE:
|
|
||||||
log_error("ERROR: QoS Policy %s has max_burst_kbps above "
|
|
||||||
"the maximal value of %s. This is not "
|
|
||||||
"supported." %
|
|
||||||
(policy['id'], rule['max_burst_kbps']))
|
|
||||||
|
|
||||||
# L2GW is not supported with the policy plugin
|
|
||||||
try:
|
|
||||||
l2gws = admin_context.session.query(l2gateway_models.L2Gateway).all()
|
|
||||||
except Exception:
|
|
||||||
# L2GW DB was not initialized
|
|
||||||
pass
|
|
||||||
else:
|
|
||||||
if len(l2gws):
|
|
||||||
log_error("ERROR: Found %s L2Gws: %s. Networking-l2gw is not "
|
|
||||||
"supported." % (len(l2gws), [l2gw.id for l2gw in l2gws]))
|
|
||||||
|
|
||||||
LOG.info("\nPre-migration validation is complete")
|
LOG.info("\nPre-migration validation is complete")
|
||||||
if n_errors:
|
if n_errors:
|
||||||
LOG.error("Found %s errors:", n_errors)
|
LOG.info("\nFound %s errors:", n_errors)
|
||||||
for msg in all_errors:
|
for msg in all_errors:
|
||||||
LOG.error(msg)
|
LOG.info(msg)
|
||||||
if n_warnings:
|
if n_warnings:
|
||||||
LOG.warning("Found %s warnings:", n_warnings)
|
LOG.info("\nFound %s warnings:", n_warnings)
|
||||||
for msg in all_warnings:
|
for msg in all_warnings:
|
||||||
LOG.warning(msg)
|
LOG.info(msg)
|
||||||
|
|
||||||
if out_file:
|
if out_file:
|
||||||
f = open(out_file, "w")
|
f = open(out_file, "w")
|
||||||
@ -497,12 +560,12 @@ def validate_config_for_migration(resource, event, trigger, **kwargs):
|
|||||||
|
|
||||||
if n_errors > 0:
|
if n_errors > 0:
|
||||||
plural = n_errors > 1
|
plural = n_errors > 1
|
||||||
LOG.error("The NSX-V plugin configuration is not ready to be "
|
LOG.info("\nThe NSX-V plugin configuration is not ready to be "
|
||||||
"migrated to NSX-T. %s issue%s found.", n_errors,
|
"migrated to NSX-T. %s issue%s found.", n_errors,
|
||||||
's were' if plural else ' was')
|
's were' if plural else ' was')
|
||||||
sys.exit(n_errors)
|
sys.exit(n_errors)
|
||||||
|
|
||||||
LOG.info("The NSX-V plugin configuration is ready to be migrated to "
|
LOG.info("\nThe NSX-V plugin configuration is ready to be migrated to "
|
||||||
"NSX-T.")
|
"NSX-T.")
|
||||||
|
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ from neutron_lib.plugins import directory
|
|||||||
|
|
||||||
from vmware_nsx.common import config
|
from vmware_nsx.common import config
|
||||||
from vmware_nsx.db import db as nsx_db
|
from vmware_nsx.db import db as nsx_db
|
||||||
|
from vmware_nsx.db import nsxv_db
|
||||||
from vmware_nsx.extensions import projectpluginmap
|
from vmware_nsx.extensions import projectpluginmap
|
||||||
from vmware_nsx import plugin
|
from vmware_nsx import plugin
|
||||||
from vmware_nsx.plugins.nsx_v.vshield import vcns
|
from vmware_nsx.plugins.nsx_v.vshield import vcns
|
||||||
@ -274,3 +275,22 @@ def get_orphaned_networks(backend_networks):
|
|||||||
if not found:
|
if not found:
|
||||||
missing_networks.append(net)
|
missing_networks.append(net)
|
||||||
return missing_networks
|
return missing_networks
|
||||||
|
|
||||||
|
|
||||||
|
def get_router_edge_bindings():
|
||||||
|
edgeapi = NeutronDbClient()
|
||||||
|
return nsxv_db.get_nsxv_router_bindings(edgeapi.context)
|
||||||
|
|
||||||
|
|
||||||
|
def get_orphaned_edges_data():
|
||||||
|
nsxv_edges = get_nsxv_backend_edges()
|
||||||
|
neutron_edge_bindings = set()
|
||||||
|
for binding in get_router_edge_bindings():
|
||||||
|
neutron_edge_bindings.add(binding.edge_id)
|
||||||
|
|
||||||
|
return [edge for edge in nsxv_edges
|
||||||
|
if edge['id'] not in neutron_edge_bindings]
|
||||||
|
|
||||||
|
|
||||||
|
def get_orphaned_edges():
|
||||||
|
return [edge['id'] for edge in get_orphaned_edges_data()]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user