NSX|v3 Admin utils refactor + additions

- Refactor nsx-v3 admin utilities by moving some of the code to a different
file which will later be consumed by the housekeeper code as well
- Adding orphaned firewall sections list/clean utilities
- Adding a capability to detect problems in logical port address bindings
- Update the documentation

Change-Id: If6aba167c2dd1234d1bb10a8a115fcdfe13cf2f0
This commit is contained in:
Adit Sarfaty 2018-06-28 08:12:44 +03:00
parent f570c651bf
commit c0f3149c40
13 changed files with 434 additions and 275 deletions

View File

@ -351,7 +351,7 @@ Orphaned Routers
Ports
~~~~~
- List missing ports, and ports that exist on backend but without the expected switch profiles::
- List missing ports, and ports that exist on backend but without the expected switch profiles or address bindings::
nsxadmin -r ports -o list-mismatches
@ -370,7 +370,7 @@ Ports
Security Groups & NSX Security Groups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- List backed security groups::
- List NSX backend security groups::
nsxadmin -r nsx-security-groups -o list
@ -378,14 +378,14 @@ Security Groups & NSX Security Groups
nsxadmin -r security-groups -o list
- Fix mismatch sections in security group::
nsxadmin -r security-groups -o fix-mismatch
- List nsx security groups with mismatch sections::
- List security groups with sections missing on the NSX backend::
nsxadmin -r nsx-security-groups -o list-mismatches
- Fix mismatch security groups by recreating missing sections & NS groups on the NSX backend::
nsxadmin -r security-groups -o fix-mismatch
- Update NSX security groups dynamic criteria for NSXv3 CrossHairs::
nsxadmin -r nsx-security-groups -o migrate-to-dynamic-criteria
@ -393,14 +393,25 @@ Security Groups & NSX Security Groups
Firewall Sections
~~~~~~~~~~~~~~~~~
- List backed firewall sections::
- List NSX backend firewall sections::
nsxadmin -r firewall-sections -o list
- List security groups with missing sections::
- List security groups with missing sections on the NSX backend::
nsxadmin -r firewall-sections -o list-mismatches
Orphaned Firewall Sections
~~~~~~~~~~~~~~~~~~~~~~~~~~
- List orphaned firewall sections (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB)::
nsxadmin -r orphaned-firewall-sections -o nsx-list
- Delete orphaned firewall sections (exist on NSXv3 backend but don't have a corresponding binding in Neutron DB)::
nsxadmin -r orphaned-firewall-sections -o nsx-clean
Metadata Proxy
~~~~~~~~~~~~~~

View File

@ -129,9 +129,7 @@ from vmware_nsxlib.v3 import utils as nsxlib_utils
LOG = log.getLogger(__name__)
NSX_V3_PSEC_PROFILE_NAME = 'neutron_port_spoof_guard_profile'
NSX_V3_NO_PSEC_PROFILE_NAME = 'nsx-default-spoof-guard-vif-profile'
NSX_V3_DHCP_PROFILE_NAME = 'neutron_port_dhcp_profile'
NSX_V3_MAC_LEARNING_PROFILE_NAME = 'neutron_port_mac_learning_profile'
NSX_V3_FW_DEFAULT_SECTION = 'OS Default Section for Neutron Security-Groups'
NSX_V3_FW_DEFAULT_NS_GROUP = 'os_default_section_ns_group'
@ -507,12 +505,12 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
def _init_nsx_profiles(self):
LOG.debug("Initializing NSX v3 port spoofguard switching profile")
if not self._init_port_security_profile():
msg = _("Unable to initialize NSX v3 port spoofguard "
"switching profile: %s") % NSX_V3_PSEC_PROFILE_NAME
msg = _("Unable to initialize NSX v3 port spoofguard switching "
"profile: %s") % v3_utils.NSX_V3_PSEC_PROFILE_NAME
raise nsx_exc.NsxPluginException(err_msg=msg)
profile_client = self.nsxlib.switching_profile
no_psec_prof = profile_client.find_by_display_name(
NSX_V3_NO_PSEC_PROFILE_NAME)[0]
NSX_V3_NO_PSEC_PROFILE_NAME)[0]
self._no_psec_profile_id = profile_client.build_switch_profile_ids(
profile_client, no_psec_prof)[0]
@ -522,7 +520,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
except Exception as e:
msg = (_("Unable to initialize NSX v3 DHCP switching profile: "
"%(id)s. Reason: %(reason)s") % {
'id': NSX_V3_DHCP_PROFILE_NAME,
'id': v3_utils.NSX_V3_DHCP_PROFILE_NAME,
'reason': str(e)})
raise nsx_exc.NsxPluginException(err_msg=msg)
@ -672,7 +670,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
with locking.LockManager.get_lock('nsxv3_dhcp_profile_init'):
if not self._get_dhcp_security_profile():
self.nsxlib.switching_profile.create_dhcp_profile(
NSX_V3_DHCP_PROFILE_NAME, 'Neutron DHCP Security Profile',
v3_utils.NSX_V3_DHCP_PROFILE_NAME,
'Neutron DHCP Security Profile',
tags=self.nsxlib.build_v3_api_version_tag())
return self._get_dhcp_security_profile()
@ -680,7 +679,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
if hasattr(self, '_dhcp_profile') and self._dhcp_profile:
return self._dhcp_profile
profile = self.nsxlib.switching_profile.find_by_display_name(
NSX_V3_DHCP_PROFILE_NAME)
v3_utils.NSX_V3_DHCP_PROFILE_NAME)
self._dhcp_profile = nsx_resources.SwitchingProfileTypeId(
profile_type=(nsx_resources.SwitchingProfileTypes.
SWITCH_SECURITY),
@ -745,7 +744,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
if hasattr(self, '_psec_profile') and self._psec_profile:
return self._psec_profile
profile = self.nsxlib.switching_profile.find_by_display_name(
NSX_V3_PSEC_PROFILE_NAME)
v3_utils.NSX_V3_PSEC_PROFILE_NAME)
self._psec_profile = profile[0] if profile else None
return self._psec_profile
@ -763,7 +762,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
return profile
self.nsxlib.switching_profile.create_spoofguard_profile(
NSX_V3_PSEC_PROFILE_NAME, 'Neutron Port Security Profile',
v3_utils.NSX_V3_PSEC_PROFILE_NAME,
'Neutron Port Security Profile',
whitelist_ports=True, whitelist_switches=False,
tags=self.nsxlib.build_v3_api_version_tag())
return self._get_port_security_profile()

View File

@ -18,19 +18,36 @@ import random
from oslo_config import cfg
from oslo_log import log as logging
from oslo_utils import fileutils
from sqlalchemy.orm import exc
from neutron.db.models import securitygroup
from neutron import version as n_version
from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
from neutron_lib import constants as const
from neutron_lib import context as q_context
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import nsx_models
from vmware_nsx.plugins.nsx_v3 import cert_utils
from vmware_nsx.services.qos.common import utils as qos_utils
from vmware_nsxlib import v3
from vmware_nsxlib.v3 import client_cert
from vmware_nsxlib.v3 import config
from vmware_nsxlib.v3 import core_resources
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
from vmware_nsxlib.v3 import nsx_constants
NSX_NEUTRON_PLUGIN = 'NSX Neutron plugin'
OS_NEUTRON_ID_SCOPE = 'os-neutron-id'
NSX_V3_PSEC_PROFILE_NAME = 'neutron_port_spoof_guard_profile'
NSX_V3_DHCP_PROFILE_NAME = 'neutron_port_dhcp_profile'
PORT_ERROR_TYPE_MISSING = "Missing port"
PORT_ERROR_TYPE_PROFILE = "Wrong switching profiles"
PORT_ERROR_TYPE_BINDINGS = "Wrong address binding"
LOG = logging.getLogger(__name__)
@ -145,3 +162,294 @@ def get_nsxlib_wrapper(nsx_username=None, nsx_password=None, basic_auth=False):
dns_nameservers=cfg.CONF.nsx_v3.nameservers,
dns_domain=cfg.CONF.nsx_v3.dns_domain)
return v3.NsxLib(nsxlib_config)
def get_orphaned_dhcp_servers(context, plugin, nsxlib, dhcp_profile_uuid=None):
# An orphaned DHCP server means the associated neutron network
# does not exist or has no DHCP-enabled subnet.
orphaned_servers = []
server_net_pairs = []
# Find matching DHCP servers (for a given dhcp_profile_uuid).
response = nsxlib.dhcp_server.list()
for dhcp_server in response['results']:
if (dhcp_profile_uuid and
dhcp_server['dhcp_profile_id'] != dhcp_profile_uuid):
continue
found = False
neutron_obj = False
for tag in dhcp_server.get('tags', []):
if tag['scope'] == 'os-neutron-net-id':
dhcp_server['neutron_net_id'] = tag['tag']
server_net_pairs.append((dhcp_server, tag['tag']))
found = True
if tag['scope'] == 'os-api-version':
neutron_obj = True
if not found and neutron_obj:
# The associated neutron network is not defined.
dhcp_server['neutron_net_id'] = None
orphaned_servers.append(dhcp_server)
# Check if there is DHCP-enabled subnet in each network.
for dhcp_server, net_id in server_net_pairs:
try:
network = plugin.get_network(context, net_id)
except Exception:
# The associated neutron network is not found in DB.
orphaned_servers.append(dhcp_server)
continue
dhcp_enabled = False
for subnet_id in network['subnets']:
subnet = plugin.get_subnet(context, subnet_id)
if subnet['enable_dhcp']:
dhcp_enabled = True
break
if not dhcp_enabled:
orphaned_servers.append(dhcp_server)
return orphaned_servers
def delete_orphaned_dhcp_server(context, nsxlib, server):
# Delete an orphaned DHCP server:
# (1) delete the attached logical DHCP port,
# (2) delete the logical DHCP server,
# (3) clean corresponding neutron DB entry.
# Return True if it was deleted, or false + error if not
try:
response = nsxlib.logical_port.get_by_attachment('DHCP_SERVICE',
server['id'])
if response and response['result_count'] > 0:
nsxlib.logical_port.delete(response['results'][0]['id'])
nsxlib.dhcp_server.delete(server['id'])
net_id = server.get('neutron_net_id')
if net_id:
# Delete neutron_net_id -> dhcp_service_id mapping from the DB.
nsx_db.delete_neutron_nsx_service_binding(
context.session, net_id,
nsx_constants.SERVICE_DHCP)
return True, None
except Exception as e:
return False, e
def get_orphaned_networks(context, nsxlib):
nsx_switches = nsxlib.logical_switch.list()['results']
missing_networks = []
for nsx_switch in nsx_switches:
# check if it exists in the neutron DB
net_ids = nsx_db.get_net_ids(context.session, nsx_switch['id'])
if not net_ids:
# Skip non-neutron networks, by tags
neutron_net = False
for tag in nsx_switch.get('tags', []):
if tag.get('scope') == 'os-neutron-net-id':
neutron_net = True
nsx_switch['neutron_net_id'] = tag['tag']
break
if neutron_net:
missing_networks.append(nsx_switch)
return missing_networks
def get_orphaned_routers(context, nsxlib):
nsx_routers = nsxlib.logical_router.list()['results']
missing_routers = []
for nsx_router in nsx_routers:
# check if it exists in the neutron DB
neutron_id = nsx_db.get_neutron_from_nsx_router_id(context.session,
nsx_router['id'])
if not neutron_id:
# Skip non-neutron routers, by tags
for tag in nsx_router.get('tags', []):
if tag.get('scope') == 'os-neutron-router-id':
nsx_router['neutron_router_id'] = tag['tag']
missing_routers.append(nsx_router)
break
return missing_routers
def delete_orphaned_router(nsxlib, nsx_id):
# Delete an orphaned logical router from the NSX:
# (1) delete the attached ports,
# (2) delete the logical router
# Return True if it was deleted, or false + error if not
try:
# first delete its ports
ports = nsxlib.logical_router_port.get_by_router_id(nsx_id)
for port in ports:
nsxlib.logical_router_port.delete(port['id'])
nsxlib.logical_router.delete(nsx_id)
except Exception as e:
return False, e
else:
return True, None
def get_security_groups_mappings(context):
q = context.session.query(
securitygroup.SecurityGroup.name,
securitygroup.SecurityGroup.id,
nsx_models.NeutronNsxFirewallSectionMapping.nsx_id,
nsx_models.NeutronNsxSecurityGroupMapping.nsx_id).join(
nsx_models.NeutronNsxFirewallSectionMapping,
nsx_models.NeutronNsxSecurityGroupMapping).all()
sg_mappings = [{'name': mapp[0],
'id': mapp[1],
'section-id': mapp[2],
'nsx-securitygroup-id': mapp[3]}
for mapp in q]
return sg_mappings
def get_orphaned_firewall_sections(context, nsxlib):
fw_sections = nsxlib.firewall_section.list()
sg_mappings = get_security_groups_mappings(context)
orphaned_sections = []
for fw_section in fw_sections:
for sg_db in sg_mappings:
if fw_section['id'] == sg_db['section-id']:
break
else:
# Skip non-neutron sections, by tags
neutron_obj = False
for tag in fw_section.get('tags', []):
if tag['scope'] == 'os-api-version':
neutron_obj = True
if tag.get('scope') == 'os-neutron-secgr-id':
fw_section['neutron_sg_id'] = tag['tag']
if neutron_obj:
orphaned_sections.append(fw_section)
return orphaned_sections
def get_dhcp_profile_id(nsxlib):
profiles = nsxlib.switching_profile.find_by_display_name(
NSX_V3_DHCP_PROFILE_NAME)
if profiles and len(profiles) == 1:
return profiles[0]['id']
LOG.warning("Could not find DHCP profile on backend")
def get_spoofguard_profile_id(nsxlib):
profiles = nsxlib.switching_profile.find_by_display_name(
NSX_V3_PSEC_PROFILE_NAME)
if profiles and len(profiles) == 1:
return profiles[0]['id']
LOG.warning("Could not find Spoof Guard profile on backend")
def add_profile_mismatch(problems, neutron_id, nsx_id, prf_id, title):
msg = ('Wrong %(title)s profile %(prf_id)s') % {'title': title,
'prf_id': prf_id}
problems.append({'neutron_id': neutron_id,
'nsx_id': nsx_id,
'error': msg,
'error_type': PORT_ERROR_TYPE_PROFILE})
def get_port_nsx_id(session, neutron_id):
# get the nsx port id from the DB mapping
try:
mapping = (session.query(nsx_models.NeutronNsxPortMapping).
filter_by(neutron_id=neutron_id).
one())
return mapping['nsx_port_id']
except exc.NoResultFound:
pass
def get_mismatch_logical_ports(context, nsxlib, plugin, get_filters=None):
neutron_ports = plugin.get_ports(context, filters=get_filters)
# get pre-defined profile ids
dhcp_profile_id = get_dhcp_profile_id(nsxlib)
dhcp_profile_key = (
core_resources.SwitchingProfileTypes.SWITCH_SECURITY)
spoofguard_profile_id = get_spoofguard_profile_id(nsxlib)
spoofguard_profile_key = (
core_resources.SwitchingProfileTypes.SPOOF_GUARD)
qos_profile_key = core_resources.SwitchingProfileTypes.QOS
problems = []
for port in neutron_ports:
neutron_id = port['id']
# get the network nsx id from the mapping table
nsx_id = get_port_nsx_id(context.session, neutron_id)
if not nsx_id:
# skip external ports
pass
else:
try:
nsx_port = nsxlib.logical_port.get(nsx_id)
except nsxlib_exc.ResourceNotFound:
problems.append({'neutron_id': neutron_id,
'nsx_id': nsx_id,
'error': 'Missing from backend',
'error_type': PORT_ERROR_TYPE_MISSING})
continue
# Port found on backend!
# Check that it has all the expected switch profiles.
# create a dictionary of the current profiles:
profiles_dict = {}
for prf in nsx_port['switching_profile_ids']:
profiles_dict[prf['key']] = prf['value']
# DHCP port: neutron dhcp profile should be attached
# to logical ports created for neutron DHCP but not
# for native DHCP.
if (port.get('device_owner') == const.DEVICE_OWNER_DHCP and
not cfg.CONF.nsx_v3.native_dhcp_metadata):
prf_id = profiles_dict[dhcp_profile_key]
if prf_id != dhcp_profile_id:
add_profile_mismatch(problems, neutron_id, nsx_id,
prf_id, "DHCP security")
# Port with QoS policy: a matching profile should be attached
qos_policy_id = qos_utils.get_port_policy_id(context,
neutron_id)
if qos_policy_id:
qos_profile_id = nsx_db.get_switch_profile_by_qos_policy(
context.session, qos_policy_id)
prf_id = profiles_dict[qos_profile_key]
if prf_id != qos_profile_id:
add_profile_mismatch(problems, neutron_id, nsx_id,
prf_id, "QoS")
# Port with security & fixed ips/address pairs:
# neutron spoofguard profile should be attached
port_sec, has_ip = plugin._determine_port_security_and_has_ip(
context, port)
addr_pair = port.get(addr_apidef.ADDRESS_PAIRS)
if port_sec and (has_ip or addr_pair):
prf_id = profiles_dict[spoofguard_profile_key]
if prf_id != spoofguard_profile_id:
add_profile_mismatch(problems, neutron_id, nsx_id,
prf_id, "Spoof Guard")
# Check the address bindings
if port_sec:
nsx_address_bindings = nsx_port.get('address_bindings', [])
nsx_ips = [x['ip_address'] for x in nsx_address_bindings]
nsx_macs = [x['mac_address'] for x in nsx_address_bindings]
neutron_ips = [x['ip_address']
for x in port.get('fixed_ips', [])]
neutron_mac = port['mac_address']
different_macs = [mac for mac in nsx_macs
if mac != neutron_mac]
if (len(nsx_ips) != len(neutron_ips) or
set(nsx_ips) != set(neutron_ips)):
problems.append({'neutron_id': neutron_id,
'nsx_id': nsx_id,
'port': port,
'error': 'Different IP address bindings',
'error_type': PORT_ERROR_TYPE_BINDINGS})
elif different_macs:
problems.append({'neutron_id': neutron_id,
'nsx_id': nsx_id,
'port': port,
'error': 'Different MAC address bindings',
'error_type': PORT_ERROR_TYPE_BINDINGS})
return problems

View File

@ -45,6 +45,7 @@ LB_VIRTUAL_SERVERS = 'lb-virtual-servers'
LB_POOLS = 'lb-pools'
LB_MONITORS = 'lb-monitors'
RATE_LIMIT = 'rate-limit'
ORPHANED_FIREWALL_SECTIONS = 'orphaned-firewall-sections'
# NSXV only Resource Constants
EDGES = 'edges'

View File

@ -79,12 +79,12 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
if netaddr.IPNetwork(fixed_ip['ip_address']).version == 6:
continue
network_id = port['network_id']
subnet = neutron_client.get_subnet(fixed_ip['subnet_id'])
subnet = neutron_client.get_subnet(None, fixed_ip['subnet_id'])
if device_owner == const.DEVICE_OWNER_DHCP:
# For each DHCP-enabled network, create a logical DHCP server
# and update the attachment type to DHCP on the corresponding
# logical port of the Neutron DHCP port.
network = neutron_client.get_network(port['network_id'])
network = neutron_client.get_network(None, port['network_id'])
net_tags = nsxlib.build_v3_tags_payload(
network, resource_type='os-neutron-net-id',
project_name='admin')
@ -132,7 +132,7 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
options = {'option121': {'static_routes': [
{'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route,
'next_hop': ip}]}}
subnet = neutron_client.get_subnet(subnet_id)
subnet = neutron_client.get_subnet(None, subnet_id)
binding = nsxlib.dhcp_server.create_binding(
dhcp_server_id, mac, ip, hostname,
cfg.CONF.nsx_v3.dhcp_lease_time, options,

View File

@ -18,13 +18,12 @@ from oslo_config import cfg
from oslo_log import log as logging
from vmware_nsx.common import utils as nsx_utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
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.nsxv3.resources import utils
import vmware_nsx.shell.resources as shell
from vmware_nsxlib.v3 import nsx_constants
LOG = logging.getLogger(__name__)
neutron_client = utils.NeutronDbClient()
@ -43,52 +42,6 @@ def _get_dhcp_profile_uuid(**kwargs):
cfg.CONF.nsx_v3.dhcp_profile)
def _get_orphaned_dhcp_servers(dhcp_profile_uuid):
# An orphaned DHCP server means the associated neutron network
# does not exist or has no DHCP-enabled subnet.
orphaned_servers = []
server_net_pairs = []
# Find matching DHCP servers for a given dhcp_profile_uuid.
nsxlib = utils.get_connected_nsxlib()
response = nsxlib.dhcp_server.list()
for dhcp_server in response['results']:
if dhcp_server['dhcp_profile_id'] != dhcp_profile_uuid:
continue
found = False
for tag in dhcp_server.get('tags', []):
if tag['scope'] == 'os-neutron-net-id':
server_net_pairs.append((dhcp_server, tag['tag']))
found = True
break
if not found:
# The associated neutron network is not defined.
dhcp_server['neutron_net_id'] = None
orphaned_servers.append(dhcp_server)
# Check if there is DHCP-enabled subnet in each network.
for dhcp_server, net_id in server_net_pairs:
try:
network = neutron_client.get_network(net_id)
except Exception:
# The associated neutron network is not found in DB.
dhcp_server['neutron_net_id'] = None
orphaned_servers.append(dhcp_server)
continue
dhcp_enabled = False
for subnet_id in network['subnets']:
subnet = neutron_client.get_subnet(subnet_id)
if subnet['enable_dhcp']:
dhcp_enabled = True
break
if not dhcp_enabled:
dhcp_server['neutron_net_id'] = net_id
orphaned_servers.append(dhcp_server)
return orphaned_servers
@admin_utils.output_header
def nsx_list_orphaned_dhcp_servers(resource, event, trigger, **kwargs):
"""List logical DHCP servers without associated DHCP-enabled subnet."""
@ -105,10 +58,13 @@ def nsx_list_orphaned_dhcp_servers(resource, event, trigger, **kwargs):
LOG.error("dhcp_profile_uuid is not defined")
return
orphaned_servers = _get_orphaned_dhcp_servers(dhcp_profile_uuid)
LOG.info(formatters.output_formatter(constants.ORPHANED_DHCP_SERVERS,
orphaned_servers,
['id', 'neutron_net_id']))
orphaned_servers = v3_utils.get_orphaned_dhcp_servers(
context.get_admin_context(),
neutron_client, nsxlib, dhcp_profile_uuid)
LOG.info(formatters.output_formatter(
constants.ORPHANED_DHCP_SERVERS,
orphaned_servers,
['id', 'neutron_net_id', 'display_name']))
@admin_utils.output_header
@ -136,25 +92,18 @@ def nsx_clean_orphaned_dhcp_servers(resource, event, trigger, **kwargs):
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
cfg.CONF.set_override('dhcp_profile', dhcp_profile_uuid, 'nsx_v3')
orphaned_servers = _get_orphaned_dhcp_servers(dhcp_profile_uuid)
orphaned_servers = v3_utils.get_orphaned_dhcp_servers(
context.get_admin_context(),
neutron_client, nsxlib, dhcp_profile_uuid)
for server in orphaned_servers:
try:
response = nsxlib.logical_port.get_by_attachment('DHCP_SERVICE',
server['id'])
if response and response['result_count'] > 0:
nsxlib.logical_port.delete(response['results'][0]['id'])
nsxlib.dhcp_server.delete(server['id'])
net_id = server.get('neutron_net_id')
if net_id:
# Delete neutron_net_id -> dhcp_service_id mapping from the DB.
nsx_db.delete_neutron_nsx_service_binding(
context.get_admin_context().session, net_id,
nsx_constants.SERVICE_DHCP)
success, error = v3_utils.delete_orphaned_dhcp_server(
context.get_admin_context(), nsxlib, server)
if success:
LOG.info("Removed orphaned DHCP server %s", server['id'])
except Exception as e:
else:
LOG.error("Failed to clean orphaned DHCP server %(id)s. "
"Exception: %(e)s", {'id': server['id'], 'e': e})
"Exception: %(e)s", {'id': server['id'], 'e': error})
registry.subscribe(nsx_list_orphaned_dhcp_servers,

View File

@ -41,7 +41,7 @@ def _is_metadata_network(network):
# If a Neutron network has only one subnet with 169.254.169.252/30 CIDR,
# then it is an internal metadata network.
if len(network['subnets']) == 1:
subnet = neutron_client.get_subnet(network['subnets'][0])
subnet = neutron_client.get_subnet(None, network['subnets'][0])
if subnet['cidr'] == nsx_rpc.METADATA_SUBNET_CIDR:
return True
return False

View File

@ -15,6 +15,7 @@
import sys
from vmware_nsx.db import db as nsx_db
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
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
@ -75,20 +76,8 @@ def list_missing_networks(resource, event, trigger, **kwargs):
@admin_utils.output_header
def list_orphaned_networks(resource, event, trigger, **kwargs):
nsxlib = utils.get_connected_nsxlib()
nsx_switches = nsxlib.logical_switch.list()['results']
missing_networks = []
for nsx_switch in nsx_switches:
# check if it exists in the neutron DB
if not neutron_client.lswitch_id_to_net_id(nsx_switch['id']):
# Skip non-neutron networks, by tags
neutron_net = False
for tag in nsx_switch.get('tags', []):
if tag.get('scope') == 'os-neutron-net-id':
neutron_net = True
break
if neutron_net:
missing_networks.append(nsx_switch)
admin_cxt = neutron_context.get_admin_context()
missing_networks = v3_utils.get_orphaned_networks(admin_cxt, nsxlib)
LOG.info(formatters.output_formatter(constants.ORPHANED_NETWORKS,
missing_networks,
['id', 'display_name']))

View File

@ -12,23 +12,18 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from oslo_log import log as logging
from sqlalchemy.orm import exc
from vmware_nsx.common import utils as nsx_utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import nsx_models
from vmware_nsx.dvs import dvs
from vmware_nsx.plugins.nsx_v3 import plugin
from vmware_nsx.services.qos.common import utils as qos_utils
from vmware_nsx.plugins.nsx_v3 import utils as plugin_utils
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.nsxv3.resources import utils as v3_utils
from vmware_nsx.shell import resources as shell
from vmware_nsxlib.v3 import core_resources
from vmware_nsxlib.v3 import exceptions as nsx_exc
from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts
from vmware_nsxlib.v3 import resources
@ -38,7 +33,6 @@ from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db import db_base_plugin_v2
from neutron.db import l3_db
from neutron.db import portsecurity_db
from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
from neutron_lib.callbacks import registry
from neutron_lib import constants as const
from neutron_lib import context as neutron_context
@ -59,17 +53,6 @@ class PortsPlugin(db_base_plugin_v2.NeutronDbPluginV2,
directory.add_plugin(plugin_constants.CORE, None)
def get_port_nsx_id(session, neutron_id):
# get the nsx port id from the DB mapping
try:
mapping = (session.query(nsx_models.NeutronNsxPortMapping).
filter_by(neutron_id=neutron_id).
one())
return mapping['nsx_port_id']
except exc.NoResultFound:
pass
def get_network_nsx_id(session, neutron_id):
# get the nsx switch id from the DB mapping
mappings = nsx_db.get_nsx_switch_ids(session, neutron_id)
@ -84,111 +67,17 @@ def get_network_nsx_id(session, neutron_id):
return mappings[0]
def get_port_and_profile_clients():
_nsx_client = v3_utils.get_nsxv3_client()
return (resources.LogicalPort(_nsx_client),
core_resources.NsxLibSwitchingProfile(_nsx_client))
def get_dhcp_profile_id(profile_client):
profiles = profile_client.find_by_display_name(
plugin.NSX_V3_DHCP_PROFILE_NAME)
if profiles and len(profiles) == 1:
return profiles[0]['id']
LOG.warning("Could not find DHCP profile on backend")
def get_spoofguard_profile_id(profile_client):
profiles = profile_client.find_by_display_name(
plugin.NSX_V3_PSEC_PROFILE_NAME)
if profiles and len(profiles) == 1:
return profiles[0]['id']
LOG.warning("Could not find Spoof Guard profile on backend")
def add_profile_mismatch(problems, neutron_id, nsx_id, prf_id, title):
msg = ('Wrong %(title)s profile %(prf_id)s') % {'title': title,
'prf_id': prf_id}
problems.append({'neutron_id': neutron_id,
'nsx_id': nsx_id,
'error': msg})
@admin_utils.output_header
def list_missing_ports(resource, event, trigger, **kwargs):
"""List neutron ports that are missing the NSX backend port
And ports with wrong switch profiles
And ports with wrong switch profiles or bindings
"""
admin_cxt = neutron_context.get_admin_context()
filters = v3_utils.get_plugin_filters(admin_cxt)
nsxlib = v3_utils.get_connected_nsxlib()
with PortsPlugin() as plugin:
neutron_ports = plugin.get_ports(admin_cxt, filters=filters)
port_client, profile_client = get_port_and_profile_clients()
# get pre-defined profile ids
dhcp_profile_id = get_dhcp_profile_id(profile_client)
dhcp_profile_key = (
core_resources.SwitchingProfileTypes.SWITCH_SECURITY)
spoofguard_profile_id = get_spoofguard_profile_id(profile_client)
spoofguard_profile_key = (
core_resources.SwitchingProfileTypes.SPOOF_GUARD)
qos_profile_key = core_resources.SwitchingProfileTypes.QOS
problems = []
for port in neutron_ports:
neutron_id = port['id']
# get the network nsx id from the mapping table
nsx_id = get_port_nsx_id(admin_cxt.session, neutron_id)
if not nsx_id:
# skip external ports
pass
else:
try:
nsx_port = port_client.get(nsx_id)
except nsx_exc.ResourceNotFound:
problems.append({'neutron_id': neutron_id,
'nsx_id': nsx_id,
'error': 'Missing from backend'})
continue
# Port found on backend!
# Check that it has all the expected switch profiles.
# create a dictionary of the current profiles:
profiles_dict = {}
for prf in nsx_port['switching_profile_ids']:
profiles_dict[prf['key']] = prf['value']
# DHCP port: neutron dhcp profile should be attached
# to logical ports created for neutron DHCP but not
# for native DHCP.
if (port.get('device_owner') == const.DEVICE_OWNER_DHCP and
not cfg.CONF.nsx_v3.native_dhcp_metadata):
prf_id = profiles_dict[dhcp_profile_key]
if prf_id != dhcp_profile_id:
add_profile_mismatch(problems, neutron_id, nsx_id,
prf_id, "DHCP security")
# Port with QoS policy: a matching profile should be attached
qos_policy_id = qos_utils.get_port_policy_id(admin_cxt,
neutron_id)
if qos_policy_id:
qos_profile_id = nsx_db.get_switch_profile_by_qos_policy(
admin_cxt.session, qos_policy_id)
prf_id = profiles_dict[qos_profile_key]
if prf_id != qos_profile_id:
add_profile_mismatch(problems, neutron_id, nsx_id,
prf_id, "QoS")
# Port with security & fixed ips/address pairs:
# neutron spoofguard profile should be attached
port_sec, has_ip = plugin._determine_port_security_and_has_ip(
admin_cxt, port)
addr_pair = port.get(addr_apidef.ADDRESS_PAIRS)
if port_sec and (has_ip or addr_pair):
prf_id = profiles_dict[spoofguard_profile_key]
if prf_id != spoofguard_profile_id:
add_profile_mismatch(problems, neutron_id, nsx_id,
prf_id, "Spoof Guard")
problems = plugin_utils.get_mismatch_logical_ports(
admin_cxt, nsxlib, plugin, filters)
if len(problems) > 0:
title = ("Found internal ports misconfiguration on the "
@ -365,7 +254,8 @@ def tag_default_ports(resource, event, trigger, **kwargs):
for port in neutron_ports:
neutron_id = port['id']
# get the network nsx id from the mapping table
nsx_id = get_port_nsx_id(admin_cxt.session, neutron_id)
nsx_id = plugin_utils.get_port_nsx_id(admin_cxt.session,
neutron_id)
if not nsx_id:
continue
device_owner = port['device_owner']

View File

@ -16,6 +16,7 @@ import sys
from vmware_nsx.common import utils as nsx_utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
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
@ -115,17 +116,8 @@ def update_nat_rules(resource, event, trigger, **kwargs):
@admin_utils.output_header
def list_orphaned_routers(resource, event, trigger, **kwargs):
nsxlib = utils.get_connected_nsxlib()
nsx_routers = nsxlib.logical_router.list()['results']
missing_routers = []
for nsx_router in nsx_routers:
# check if it exists in the neutron DB
if not neutron_client.lrouter_id_to_router_id(nsx_router['id']):
# Skip non-neutron routers, by tags
for tag in nsx_router.get('tags', []):
if tag.get('scope') == 'os-neutron-router-id':
missing_routers.append(nsx_router)
break
admin_cxt = neutron_context.get_admin_context()
missing_routers = v3_utils.get_orphaned_routers(admin_cxt, nsxlib)
LOG.info(formatters.output_formatter(constants.ORPHANED_ROUTERS,
missing_routers,
['id', 'display_name']))
@ -154,15 +146,10 @@ def delete_backend_router(resource, event, trigger, **kwargs):
return
# try to delete it
try:
# first delete its ports
ports = nsxlib.logical_router_port.get_by_router_id(nsx_id)
for port in ports:
nsxlib.logical_router_port.delete(port['id'])
nsxlib.logical_router.delete(nsx_id)
except Exception as e:
success, error = v3_utils.delete_orphaned_router(nsxlib, nsx_id)
if not success:
LOG.error("Failed to delete backend router %(id)s : %(e)s.", {
'id': nsx_id, 'e': e})
'id': nsx_id, 'e': error})
return
# Verify that the router was deleted since the backend does not always

View File

@ -14,7 +14,6 @@
from neutron.db import api as db_api
from neutron.db import common_db_mixin as common_db
from neutron.db.models import securitygroup
from neutron.db import securitygroups_db
from neutron_lib.callbacks import registry
from neutron_lib import context as neutron_context
@ -24,10 +23,10 @@ from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import nsx_models
from vmware_nsx.extensions import providersecuritygroup as provider_sg
from vmware_nsx.extensions import securitygrouplogging as sg_logging
from vmware_nsx.plugins.nsx_v3 import utils as plugin_utils
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.nsxv3.resources import ports
from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils
from vmware_nsx.shell import resources as shell
from vmware_nsxlib.v3 import nsx_constants as consts
@ -82,21 +81,6 @@ class NeutronSecurityGroupApi(securitygroups_db.SecurityGroupDbMixin,
if sg_mapping:
self.context.session.delete(sg_mapping)
def get_security_groups_mappings(self):
q = self.context.session.query(
securitygroup.SecurityGroup.name,
securitygroup.SecurityGroup.id,
nsx_models.NeutronNsxFirewallSectionMapping.nsx_id,
nsx_models.NeutronNsxSecurityGroupMapping.nsx_id).join(
nsx_models.NeutronNsxFirewallSectionMapping,
nsx_models.NeutronNsxSecurityGroupMapping).all()
sg_mappings = [{'name': mapp[0],
'id': mapp[1],
'section-id': mapp[2],
'nsx-securitygroup-id': mapp[3]}
for mapp in q]
return sg_mappings
def get_logical_port_id(self, port_id):
mapping = self.context.session.query(
nsx_models.NeutronNsxPortMapping).filter_by(
@ -116,7 +100,8 @@ def _log_info(resource, data, attrs=['display_name', 'id']):
@admin_utils.list_handler(constants.SECURITY_GROUPS)
@admin_utils.output_header
def list_security_groups_mappings(resource, event, trigger, **kwargs):
sg_mappings = neutron_sg.get_security_groups_mappings()
"""List neutron security groups"""
sg_mappings = plugin_utils.get_security_groups_mappings(neutron_sg.context)
_log_info(constants.SECURITY_GROUPS,
sg_mappings,
attrs=['name', 'id', 'section-id', 'nsx-securitygroup-id'])
@ -126,6 +111,7 @@ def list_security_groups_mappings(resource, event, trigger, **kwargs):
@admin_utils.list_handler(constants.FIREWALL_SECTIONS)
@admin_utils.output_header
def nsx_list_dfw_sections(resource, event, trigger, **kwargs):
"""List NSX backend firewall sections"""
nsxlib = v3_utils.get_connected_nsxlib()
fw_sections = nsxlib.firewall_section.list()
_log_info(constants.FIREWALL_SECTIONS, fw_sections)
@ -135,6 +121,7 @@ def nsx_list_dfw_sections(resource, event, trigger, **kwargs):
@admin_utils.list_handler(constants.FIREWALL_NSX_GROUPS)
@admin_utils.output_header
def nsx_list_security_groups(resource, event, trigger, **kwargs):
"""List NSX backend security groups"""
nsxlib = v3_utils.get_connected_nsxlib()
nsx_secgroups = nsxlib.ns_group.list()
_log_info(constants.FIREWALL_NSX_GROUPS, nsx_secgroups)
@ -144,7 +131,7 @@ def nsx_list_security_groups(resource, event, trigger, **kwargs):
def _find_missing_security_groups():
nsxlib = v3_utils.get_connected_nsxlib()
nsx_secgroups = nsxlib.ns_group.list()
sg_mappings = neutron_sg.get_security_groups_mappings()
sg_mappings = plugin_utils.get_security_groups_mappings(neutron_sg.context)
missing_secgroups = {}
for sg_db in sg_mappings:
for nsx_sg in nsx_secgroups:
@ -158,6 +145,7 @@ def _find_missing_security_groups():
@admin_utils.list_mismatches_handler(constants.FIREWALL_NSX_GROUPS)
@admin_utils.output_header
def list_missing_security_groups(resource, event, trigger, **kwargs):
"""List security groups with sections missing on the NSX backend"""
sgs_with_missing_nsx_group = _find_missing_security_groups()
missing_securitgroups_info = [
{'securitygroup-name': sg['name'],
@ -174,7 +162,7 @@ def list_missing_security_groups(resource, event, trigger, **kwargs):
def _find_missing_sections():
nsxlib = v3_utils.get_connected_nsxlib()
fw_sections = nsxlib.firewall_section.list()
sg_mappings = neutron_sg.get_security_groups_mappings()
sg_mappings = plugin_utils.get_security_groups_mappings(neutron_sg.context)
missing_sections = {}
for sg_db in sg_mappings:
for fw_section in fw_sections:
@ -188,6 +176,7 @@ def _find_missing_sections():
@admin_utils.list_mismatches_handler(constants.FIREWALL_SECTIONS)
@admin_utils.output_header
def list_missing_firewall_sections(resource, event, trigger, **kwargs):
"""List security groups with missing sections on the NSX backend"""
sgs_with_missing_section = _find_missing_sections()
missing_sections_info = [{'securitygroup-name': sg['name'],
'securitygroup-id': sg['id'],
@ -201,6 +190,9 @@ def list_missing_firewall_sections(resource, event, trigger, **kwargs):
@admin_utils.fix_mismatches_handler(constants.SECURITY_GROUPS)
@admin_utils.output_header
def fix_security_groups(resource, event, trigger, **kwargs):
"""Fix mismatch security groups by recreating missing sections & NS groups
on the NSX backend
"""
context_ = neutron_context.get_admin_context()
inconsistent_secgroups = _find_missing_sections()
inconsistent_secgroups.update(_find_missing_security_groups())
@ -252,7 +244,6 @@ def fix_security_groups(resource, event, trigger, **kwargs):
def _update_ports_dynamic_criteria_tags():
nsxlib = v3_utils.get_connected_nsxlib()
port_client, _ = ports.get_port_and_profile_clients()
for port in neutron_db.get_ports():
secgroups = neutron_sg.get_port_security_groups(port['id'])
# Nothing to do with ports that are not associated with any sec-group.
@ -261,7 +252,8 @@ def _update_ports_dynamic_criteria_tags():
_, lport_id = neutron_db.get_lswitch_and_lport_id(port['id'])
criteria_tags = nsxlib.ns_group.get_lport_tags(secgroups)
port_client.update(lport_id, False, tags_update=criteria_tags)
nsxlib.logical_port.update(
lport_id, False, tags_update=criteria_tags)
def _update_security_group_dynamic_criteria():
@ -286,6 +278,7 @@ def _update_security_group_dynamic_criteria():
@admin_utils.output_header
def migrate_nsgroups_to_dynamic_criteria(resource, event, trigger, **kwargs):
"""Update NSX security groups dynamic criteria for NSXv3 CrossHairs"""
nsxlib = v3_utils.get_connected_nsxlib()
if not nsxlib.feature_supported(consts.FEATURE_DYNAMIC_CRITERIA):
LOG.error("Dynamic criteria grouping feature isn't supported by "
@ -297,6 +290,30 @@ def migrate_nsgroups_to_dynamic_criteria(resource, event, trigger, **kwargs):
_update_security_group_dynamic_criteria()
def list_orphaned_sections(resource, event, trigger, **kwargs):
"""List orphaned firewall sections"""
nsxlib = v3_utils.get_connected_nsxlib()
orphaned_sections = plugin_utils.get_orphaned_firewall_sections(
neutron_sg.context, nsxlib)
_log_info(constants.ORPHANED_FIREWALL_SECTIONS, orphaned_sections,
attrs=['id', 'display_name'])
def clean_orphaned_sections(resource, event, trigger, **kwargs):
"""Delete orphaned firewall sections from the NSX backend"""
nsxlib = v3_utils.get_connected_nsxlib()
orphaned_sections = plugin_utils.get_orphaned_firewall_sections(
neutron_sg.context, nsxlib)
for sec in orphaned_sections:
try:
nsxlib.firewall_section.delete(sec['id'])
except Exception as e:
LOG.error("Failed to delete backend firewall section %(id)s : "
"%(e)s.", {'id': sec['id'], 'e': e})
else:
LOG.info("Backend firewall section %s was deleted.", sec['id'])
registry.subscribe(migrate_nsgroups_to_dynamic_criteria,
constants.FIREWALL_NSX_GROUPS,
shell.Operations.MIGRATE_TO_DYNAMIC_CRITERIA.value)
@ -304,3 +321,11 @@ registry.subscribe(migrate_nsgroups_to_dynamic_criteria,
registry.subscribe(fix_security_groups,
constants.FIREWALL_SECTIONS,
shell.Operations.NSX_UPDATE.value)
registry.subscribe(list_orphaned_sections,
constants.ORPHANED_FIREWALL_SECTIONS,
shell.Operations.NSX_LIST.value)
registry.subscribe(clean_orphaned_sections,
constants.ORPHANED_FIREWALL_SECTIONS,
shell.Operations.NSX_CLEAN.value)

View File

@ -92,24 +92,19 @@ class NeutronDbClient(db_base_plugin_v2.NeutronDbPluginV2):
return super(NeutronDbClient, self).get_networks(
self.context, filters=filters, fields=fields)
def get_network(self, network_id):
return super(NeutronDbClient, self).get_network(
self.context, network_id)
def get_network(self, context, network_id):
if not context:
context = self.context
return super(NeutronDbClient, self).get_network(context, network_id)
def get_subnet(self, subnet_id):
return super(NeutronDbClient, self).get_subnet(self.context, subnet_id)
def get_subnet(self, context, subnet_id):
if not context:
context = self.context
return super(NeutronDbClient, self).get_subnet(context, subnet_id)
def get_lswitch_and_lport_id(self, port_id):
return nsx_db.get_nsx_switch_and_port_id(self.context.session, port_id)
def lswitch_id_to_net_id(self, lswitch_id):
net_ids = nsx_db.get_net_ids(self.context.session, lswitch_id)
return net_ids[0] if net_ids else None
def lrouter_id_to_router_id(self, lrouter_id):
return nsx_db.get_neutron_from_nsx_router_id(self.context.session,
lrouter_id)
def net_id_to_lswitch_id(self, net_id):
lswitch_ids = nsx_db.get_nsx_switch_ids(self.context.session, net_id)
return lswitch_ids[0] if lswitch_ids else None

View File

@ -89,6 +89,10 @@ nsxv3_resources = {
Operations.LIST.value,
Operations.LIST_MISMATCHES.value,
Operations.MIGRATE_TO_DYNAMIC_CRITERIA.value]),
constants.ORPHANED_FIREWALL_SECTIONS: Resource(
constants.ORPHANED_FIREWALL_SECTIONS, [
Operations.NSX_LIST.value,
Operations.NSX_CLEAN.value]),
constants.NETWORKS: Resource(constants.NETWORKS,
[Operations.LIST_MISMATCHES.value]),
constants.PORTS: Resource(constants.PORTS,