Aaron Rosen 86118f6692 nxv3: mass refactor of nsxlib
This patch refactors the current codebase to be more modular
and testable. The main changes are:

  - pull out all of the profile setup logic from the __init__
    method to it's own method _init_nsx_profiles method to make
    testing the code easier.

  - refactors the nsxlib.v3 code to break out all neutron related
    exceptions and cleans up the interface so we can make nsxlib.v3
    it's own standalone library eventually.

To improve:

  - Currently we have nsxlib.v3.dfw_api and nsxlib.v3.firewall,
    we should refactor this code and merge them into one file.

  - refactor nsxlib to section of each api component to it's own
    subclass. For example, nsxlib().port.create() rather than
    nsxlib().create_port(). I think this would be most useful
    for the security group/firewall integration as there are many
    methods there that are needed to interface with nsx as the security
    group feature is requires the most orchestration with nsx.
    Breaking them into a sub class will make things more easy to understand.

Change-Id: If2fe1e014b78703ff0a9cdff1e4e8d45f3a4a16d
2016-08-19 12:28:20 +00:00

174 lines
6.8 KiB
Python

# Copyright 2016 VMware, Inc. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import logging
from sqlalchemy.orm import exc
from vmware_nsx._i18n import _LI, _LW
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.nsxlib.v3 import resources
from vmware_nsx.plugins.nsx_v3 import plugin
from vmware_nsx.services.qos.common import utils as qos_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 neutron.callbacks import registry
from neutron import context as neutron_context
from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db import db_base_plugin_v2
from neutron.db import portsecurity_db
from neutron.extensions import allowedaddresspairs
from neutron_lib import constants as const
LOG = logging.getLogger(__name__)
class PortsPlugin(db_base_plugin_v2.NeutronDbPluginV2,
portsecurity_db.PortSecurityDbMixin,
addr_pair_db.AllowedAddressPairsMixin):
pass
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_port_and_profile_clients():
_nsx_client = v3_utils.get_nsxv3_client()
return (resources.LogicalPort(_nsx_client),
resources.SwitchingProfile(_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(_LW("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(_LW("Could not find Spoof Guard profile on backend"))
def add_profile_mismatch(problems, neutron_id, nsx_id, prf_id, title):
msg = (_LI('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
"""
plugin = PortsPlugin()
admin_cxt = neutron_context.get_admin_context()
neutron_ports = plugin.get_ports(admin_cxt)
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 = resources.SwitchingProfileTypes.SWITCH_SECURITY
spoofguard_profile_id = get_spoofguard_profile_id(profile_client)
spoofguard_profile_key = resources.SwitchingProfileTypes.SPOOF_GUARD
qos_profile_key = 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': _LI('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
if port.get('device_owner') == const.DEVICE_OWNER_DHCP:
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(allowedaddresspairs.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:
title = _LI("Found internal ports misconfiguration on the "
"NSX manager:")
LOG.info(formatters.output_formatter(
title, problems,
['neutron_id', 'nsx_id', 'error']))
else:
LOG.info(_LI("All internal ports verified on the NSX manager"))
registry.subscribe(list_missing_ports,
constants.PORTS,
shell.Operations.LIST_MISMATCHES.value)