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 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 nsxadmin -r ports -o list-mismatches
@ -370,7 +370,7 @@ Ports
Security Groups & NSX Security Groups Security Groups & NSX Security Groups
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- List backed security groups:: - List NSX backend security groups::
nsxadmin -r nsx-security-groups -o list nsxadmin -r nsx-security-groups -o list
@ -378,14 +378,14 @@ Security Groups & NSX Security Groups
nsxadmin -r security-groups -o list nsxadmin -r security-groups -o list
- Fix mismatch sections in security group:: - List security groups with sections missing on the NSX backend::
nsxadmin -r security-groups -o fix-mismatch
- List nsx security groups with mismatch sections::
nsxadmin -r nsx-security-groups -o list-mismatches 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:: - Update NSX security groups dynamic criteria for NSXv3 CrossHairs::
nsxadmin -r nsx-security-groups -o migrate-to-dynamic-criteria nsxadmin -r nsx-security-groups -o migrate-to-dynamic-criteria
@ -393,14 +393,25 @@ Security Groups & NSX Security Groups
Firewall Sections Firewall Sections
~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~
- List backed firewall sections:: - List NSX backend firewall sections::
nsxadmin -r firewall-sections -o list 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 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 Metadata Proxy
~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~

View File

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

View File

@ -18,19 +18,36 @@ import random
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import fileutils 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 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 neutron_lib import context as q_context
from vmware_nsx.common import exceptions as nsx_exc 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.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 import v3
from vmware_nsxlib.v3 import client_cert from vmware_nsxlib.v3 import client_cert
from vmware_nsxlib.v3 import config 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' NSX_NEUTRON_PLUGIN = 'NSX Neutron plugin'
OS_NEUTRON_ID_SCOPE = 'os-neutron-id' 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__) 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_nameservers=cfg.CONF.nsx_v3.nameservers,
dns_domain=cfg.CONF.nsx_v3.dns_domain) dns_domain=cfg.CONF.nsx_v3.dns_domain)
return v3.NsxLib(nsxlib_config) 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_POOLS = 'lb-pools'
LB_MONITORS = 'lb-monitors' LB_MONITORS = 'lb-monitors'
RATE_LIMIT = 'rate-limit' RATE_LIMIT = 'rate-limit'
ORPHANED_FIREWALL_SECTIONS = 'orphaned-firewall-sections'
# NSXV only Resource Constants # NSXV only Resource Constants
EDGES = 'edges' 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: if netaddr.IPNetwork(fixed_ip['ip_address']).version == 6:
continue continue
network_id = port['network_id'] 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: if device_owner == const.DEVICE_OWNER_DHCP:
# For each DHCP-enabled network, create a logical DHCP server # For each DHCP-enabled network, create a logical DHCP server
# and update the attachment type to DHCP on the corresponding # and update the attachment type to DHCP on the corresponding
# logical port of the Neutron DHCP port. # 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( net_tags = nsxlib.build_v3_tags_payload(
network, resource_type='os-neutron-net-id', network, resource_type='os-neutron-net-id',
project_name='admin') project_name='admin')
@ -132,7 +132,7 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
options = {'option121': {'static_routes': [ options = {'option121': {'static_routes': [
{'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route, {'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route,
'next_hop': ip}]}} 'next_hop': ip}]}}
subnet = neutron_client.get_subnet(subnet_id) subnet = neutron_client.get_subnet(None, subnet_id)
binding = nsxlib.dhcp_server.create_binding( binding = nsxlib.dhcp_server.create_binding(
dhcp_server_id, mac, ip, hostname, dhcp_server_id, mac, ip, hostname,
cfg.CONF.nsx_v3.dhcp_lease_time, options, 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 oslo_log import log as logging
from vmware_nsx.common import utils as nsx_utils 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 constants
from vmware_nsx.shell.admin.plugins.common import formatters 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.nsxv3.resources import utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils
import vmware_nsx.shell.resources as shell import vmware_nsx.shell.resources as shell
from vmware_nsxlib.v3 import nsx_constants
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
neutron_client = utils.NeutronDbClient() neutron_client = utils.NeutronDbClient()
@ -43,52 +42,6 @@ def _get_dhcp_profile_uuid(**kwargs):
cfg.CONF.nsx_v3.dhcp_profile) 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 @admin_utils.output_header
def nsx_list_orphaned_dhcp_servers(resource, event, trigger, **kwargs): def nsx_list_orphaned_dhcp_servers(resource, event, trigger, **kwargs):
"""List logical DHCP servers without associated DHCP-enabled subnet.""" """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") LOG.error("dhcp_profile_uuid is not defined")
return return
orphaned_servers = _get_orphaned_dhcp_servers(dhcp_profile_uuid) orphaned_servers = v3_utils.get_orphaned_dhcp_servers(
LOG.info(formatters.output_formatter(constants.ORPHANED_DHCP_SERVERS, context.get_admin_context(),
neutron_client, nsxlib, dhcp_profile_uuid)
LOG.info(formatters.output_formatter(
constants.ORPHANED_DHCP_SERVERS,
orphaned_servers, orphaned_servers,
['id', 'neutron_net_id'])) ['id', 'neutron_net_id', 'display_name']))
@admin_utils.output_header @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('native_dhcp_metadata', True, 'nsx_v3')
cfg.CONF.set_override('dhcp_profile', dhcp_profile_uuid, '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: for server in orphaned_servers:
try: success, error = v3_utils.delete_orphaned_dhcp_server(
response = nsxlib.logical_port.get_by_attachment('DHCP_SERVICE', context.get_admin_context(), nsxlib, server)
server['id']) if success:
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)
LOG.info("Removed orphaned DHCP server %s", server['id']) LOG.info("Removed orphaned DHCP server %s", server['id'])
except Exception as e: else:
LOG.error("Failed to clean orphaned DHCP server %(id)s. " 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, 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, # If a Neutron network has only one subnet with 169.254.169.252/30 CIDR,
# then it is an internal metadata network. # then it is an internal metadata network.
if len(network['subnets']) == 1: 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: if subnet['cidr'] == nsx_rpc.METADATA_SUBNET_CIDR:
return True return True
return False return False

View File

@ -15,6 +15,7 @@
import sys import sys
from vmware_nsx.db import db as nsx_db 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 constants
from vmware_nsx.shell.admin.plugins.common import formatters 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
@ -75,20 +76,8 @@ def list_missing_networks(resource, event, trigger, **kwargs):
@admin_utils.output_header @admin_utils.output_header
def list_orphaned_networks(resource, event, trigger, **kwargs): def list_orphaned_networks(resource, event, trigger, **kwargs):
nsxlib = utils.get_connected_nsxlib() nsxlib = utils.get_connected_nsxlib()
nsx_switches = nsxlib.logical_switch.list()['results'] admin_cxt = neutron_context.get_admin_context()
missing_networks = [] missing_networks = v3_utils.get_orphaned_networks(admin_cxt, nsxlib)
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)
LOG.info(formatters.output_formatter(constants.ORPHANED_NETWORKS, LOG.info(formatters.output_formatter(constants.ORPHANED_NETWORKS,
missing_networks, missing_networks,
['id', 'display_name'])) ['id', 'display_name']))

View File

@ -12,23 +12,18 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from sqlalchemy.orm import exc
from vmware_nsx.common import utils as nsx_utils from vmware_nsx.common import utils as nsx_utils
from vmware_nsx.db import db as nsx_db 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.dvs import dvs
from vmware_nsx.plugins.nsx_v3 import plugin 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 constants
from vmware_nsx.shell.admin.plugins.common import formatters 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.nsxv3.resources import utils as v3_utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils
from vmware_nsx.shell import resources as shell 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 exceptions as nsx_exc
from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts
from vmware_nsxlib.v3 import resources 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 db_base_plugin_v2
from neutron.db import l3_db from neutron.db import l3_db
from neutron.db import portsecurity_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.callbacks import registry
from neutron_lib import constants as const from neutron_lib import constants as const
from neutron_lib import context as neutron_context 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) 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): def get_network_nsx_id(session, neutron_id):
# get the nsx switch id from the DB mapping # get the nsx switch id from the DB mapping
mappings = nsx_db.get_nsx_switch_ids(session, neutron_id) 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] 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 @admin_utils.output_header
def list_missing_ports(resource, event, trigger, **kwargs): def list_missing_ports(resource, event, trigger, **kwargs):
"""List neutron ports that are missing the NSX backend port """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() admin_cxt = neutron_context.get_admin_context()
filters = v3_utils.get_plugin_filters(admin_cxt) filters = v3_utils.get_plugin_filters(admin_cxt)
nsxlib = v3_utils.get_connected_nsxlib()
with PortsPlugin() as plugin: with PortsPlugin() as plugin:
neutron_ports = plugin.get_ports(admin_cxt, filters=filters) problems = plugin_utils.get_mismatch_logical_ports(
port_client, profile_client = get_port_and_profile_clients() admin_cxt, nsxlib, plugin, filters)
# 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")
if len(problems) > 0: if len(problems) > 0:
title = ("Found internal ports misconfiguration on the " title = ("Found internal ports misconfiguration on the "
@ -365,7 +254,8 @@ def tag_default_ports(resource, event, trigger, **kwargs):
for port in neutron_ports: for port in neutron_ports:
neutron_id = port['id'] neutron_id = port['id']
# get the network nsx id from the mapping table # 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: if not nsx_id:
continue continue
device_owner = port['device_owner'] 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.common import utils as nsx_utils
from vmware_nsx.db import db as nsx_db 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 constants
from vmware_nsx.shell.admin.plugins.common import formatters 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
@ -115,17 +116,8 @@ def update_nat_rules(resource, event, trigger, **kwargs):
@admin_utils.output_header @admin_utils.output_header
def list_orphaned_routers(resource, event, trigger, **kwargs): def list_orphaned_routers(resource, event, trigger, **kwargs):
nsxlib = utils.get_connected_nsxlib() nsxlib = utils.get_connected_nsxlib()
nsx_routers = nsxlib.logical_router.list()['results'] admin_cxt = neutron_context.get_admin_context()
missing_routers = [] missing_routers = v3_utils.get_orphaned_routers(admin_cxt, nsxlib)
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
LOG.info(formatters.output_formatter(constants.ORPHANED_ROUTERS, LOG.info(formatters.output_formatter(constants.ORPHANED_ROUTERS,
missing_routers, missing_routers,
['id', 'display_name'])) ['id', 'display_name']))
@ -154,15 +146,10 @@ def delete_backend_router(resource, event, trigger, **kwargs):
return return
# try to delete it # try to delete it
try: success, error = v3_utils.delete_orphaned_router(nsxlib, nsx_id)
# first delete its ports if not success:
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:
LOG.error("Failed to delete backend router %(id)s : %(e)s.", { LOG.error("Failed to delete backend router %(id)s : %(e)s.", {
'id': nsx_id, 'e': e}) 'id': nsx_id, 'e': error})
return return
# Verify that the router was deleted since the backend does not always # 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 api as db_api
from neutron.db import common_db_mixin as common_db from neutron.db import common_db_mixin as common_db
from neutron.db.models import securitygroup
from neutron.db import securitygroups_db from neutron.db import securitygroups_db
from neutron_lib.callbacks import registry from neutron_lib.callbacks import registry
from neutron_lib import context as neutron_context 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.db import nsx_models
from vmware_nsx.extensions import providersecuritygroup as provider_sg from vmware_nsx.extensions import providersecuritygroup as provider_sg
from vmware_nsx.extensions import securitygrouplogging as sg_logging 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 constants
from vmware_nsx.shell.admin.plugins.common import formatters 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.nsxv3.resources import ports
from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils from vmware_nsx.shell.admin.plugins.nsxv3.resources import utils as v3_utils
from vmware_nsx.shell import resources as shell from vmware_nsx.shell import resources as shell
from vmware_nsxlib.v3 import nsx_constants as consts from vmware_nsxlib.v3 import nsx_constants as consts
@ -82,21 +81,6 @@ class NeutronSecurityGroupApi(securitygroups_db.SecurityGroupDbMixin,
if sg_mapping: if sg_mapping:
self.context.session.delete(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): def get_logical_port_id(self, port_id):
mapping = self.context.session.query( mapping = self.context.session.query(
nsx_models.NeutronNsxPortMapping).filter_by( 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.list_handler(constants.SECURITY_GROUPS)
@admin_utils.output_header @admin_utils.output_header
def list_security_groups_mappings(resource, event, trigger, **kwargs): 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, _log_info(constants.SECURITY_GROUPS,
sg_mappings, sg_mappings,
attrs=['name', 'id', 'section-id', 'nsx-securitygroup-id']) 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.list_handler(constants.FIREWALL_SECTIONS)
@admin_utils.output_header @admin_utils.output_header
def nsx_list_dfw_sections(resource, event, trigger, **kwargs): def nsx_list_dfw_sections(resource, event, trigger, **kwargs):
"""List NSX backend firewall sections"""
nsxlib = v3_utils.get_connected_nsxlib() nsxlib = v3_utils.get_connected_nsxlib()
fw_sections = nsxlib.firewall_section.list() fw_sections = nsxlib.firewall_section.list()
_log_info(constants.FIREWALL_SECTIONS, fw_sections) _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.list_handler(constants.FIREWALL_NSX_GROUPS)
@admin_utils.output_header @admin_utils.output_header
def nsx_list_security_groups(resource, event, trigger, **kwargs): def nsx_list_security_groups(resource, event, trigger, **kwargs):
"""List NSX backend security groups"""
nsxlib = v3_utils.get_connected_nsxlib() nsxlib = v3_utils.get_connected_nsxlib()
nsx_secgroups = nsxlib.ns_group.list() nsx_secgroups = nsxlib.ns_group.list()
_log_info(constants.FIREWALL_NSX_GROUPS, nsx_secgroups) _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(): def _find_missing_security_groups():
nsxlib = v3_utils.get_connected_nsxlib() nsxlib = v3_utils.get_connected_nsxlib()
nsx_secgroups = nsxlib.ns_group.list() 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 = {} missing_secgroups = {}
for sg_db in sg_mappings: for sg_db in sg_mappings:
for nsx_sg in nsx_secgroups: 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.list_mismatches_handler(constants.FIREWALL_NSX_GROUPS)
@admin_utils.output_header @admin_utils.output_header
def list_missing_security_groups(resource, event, trigger, **kwargs): 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() sgs_with_missing_nsx_group = _find_missing_security_groups()
missing_securitgroups_info = [ missing_securitgroups_info = [
{'securitygroup-name': sg['name'], {'securitygroup-name': sg['name'],
@ -174,7 +162,7 @@ def list_missing_security_groups(resource, event, trigger, **kwargs):
def _find_missing_sections(): def _find_missing_sections():
nsxlib = v3_utils.get_connected_nsxlib() nsxlib = v3_utils.get_connected_nsxlib()
fw_sections = nsxlib.firewall_section.list() 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 = {} missing_sections = {}
for sg_db in sg_mappings: for sg_db in sg_mappings:
for fw_section in fw_sections: for fw_section in fw_sections:
@ -188,6 +176,7 @@ def _find_missing_sections():
@admin_utils.list_mismatches_handler(constants.FIREWALL_SECTIONS) @admin_utils.list_mismatches_handler(constants.FIREWALL_SECTIONS)
@admin_utils.output_header @admin_utils.output_header
def list_missing_firewall_sections(resource, event, trigger, **kwargs): 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() sgs_with_missing_section = _find_missing_sections()
missing_sections_info = [{'securitygroup-name': sg['name'], missing_sections_info = [{'securitygroup-name': sg['name'],
'securitygroup-id': sg['id'], '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.fix_mismatches_handler(constants.SECURITY_GROUPS)
@admin_utils.output_header @admin_utils.output_header
def fix_security_groups(resource, event, trigger, **kwargs): 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() context_ = neutron_context.get_admin_context()
inconsistent_secgroups = _find_missing_sections() inconsistent_secgroups = _find_missing_sections()
inconsistent_secgroups.update(_find_missing_security_groups()) 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(): def _update_ports_dynamic_criteria_tags():
nsxlib = v3_utils.get_connected_nsxlib() nsxlib = v3_utils.get_connected_nsxlib()
port_client, _ = ports.get_port_and_profile_clients()
for port in neutron_db.get_ports(): for port in neutron_db.get_ports():
secgroups = neutron_sg.get_port_security_groups(port['id']) secgroups = neutron_sg.get_port_security_groups(port['id'])
# Nothing to do with ports that are not associated with any sec-group. # 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']) _, lport_id = neutron_db.get_lswitch_and_lport_id(port['id'])
criteria_tags = nsxlib.ns_group.get_lport_tags(secgroups) 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(): def _update_security_group_dynamic_criteria():
@ -286,6 +278,7 @@ def _update_security_group_dynamic_criteria():
@admin_utils.output_header @admin_utils.output_header
def migrate_nsgroups_to_dynamic_criteria(resource, event, trigger, **kwargs): 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() nsxlib = v3_utils.get_connected_nsxlib()
if not nsxlib.feature_supported(consts.FEATURE_DYNAMIC_CRITERIA): if not nsxlib.feature_supported(consts.FEATURE_DYNAMIC_CRITERIA):
LOG.error("Dynamic criteria grouping feature isn't supported by " 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() _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, registry.subscribe(migrate_nsgroups_to_dynamic_criteria,
constants.FIREWALL_NSX_GROUPS, constants.FIREWALL_NSX_GROUPS,
shell.Operations.MIGRATE_TO_DYNAMIC_CRITERIA.value) shell.Operations.MIGRATE_TO_DYNAMIC_CRITERIA.value)
@ -304,3 +321,11 @@ registry.subscribe(migrate_nsgroups_to_dynamic_criteria,
registry.subscribe(fix_security_groups, registry.subscribe(fix_security_groups,
constants.FIREWALL_SECTIONS, constants.FIREWALL_SECTIONS,
shell.Operations.NSX_UPDATE.value) 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( return super(NeutronDbClient, self).get_networks(
self.context, filters=filters, fields=fields) self.context, filters=filters, fields=fields)
def get_network(self, network_id): def get_network(self, context, network_id):
return super(NeutronDbClient, self).get_network( if not context:
self.context, network_id) context = self.context
return super(NeutronDbClient, self).get_network(context, network_id)
def get_subnet(self, subnet_id): def get_subnet(self, context, subnet_id):
return super(NeutronDbClient, self).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): def get_lswitch_and_lport_id(self, port_id):
return nsx_db.get_nsx_switch_and_port_id(self.context.session, 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): def net_id_to_lswitch_id(self, net_id):
lswitch_ids = nsx_db.get_nsx_switch_ids(self.context.session, net_id) lswitch_ids = nsx_db.get_nsx_switch_ids(self.context.session, net_id)
return lswitch_ids[0] if lswitch_ids else None return lswitch_ids[0] if lswitch_ids else None

View File

@ -89,6 +89,10 @@ nsxv3_resources = {
Operations.LIST.value, Operations.LIST.value,
Operations.LIST_MISMATCHES.value, Operations.LIST_MISMATCHES.value,
Operations.MIGRATE_TO_DYNAMIC_CRITERIA.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, constants.NETWORKS: Resource(constants.NETWORKS,
[Operations.LIST_MISMATCHES.value]), [Operations.LIST_MISMATCHES.value]),
constants.PORTS: Resource(constants.PORTS, constants.PORTS: Resource(constants.PORTS,