26135f34ac
This patch retires the NSX MH plugin by: - Deleting the nsx_mh plugin and unit test code. - Using the NSX-V and V3 plugin test base classes where needed. - Removing any extensions that are MH specific. Change-Id: Idf65e44c301e790ca4ea69a6a8735aa0309a0dcc
195 lines
7.9 KiB
Python
195 lines
7.9 KiB
Python
# Copyright 2013 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.
|
|
|
|
from neutron_lib.api.definitions import multiprovidernet as mpnet_apidef
|
|
from neutron_lib.api.definitions import provider_net as pnet
|
|
from neutron_lib.api import validators
|
|
from neutron_lib import constants
|
|
from oslo_log import log
|
|
|
|
from vmware_nsx.api_client import client
|
|
from vmware_nsx.common import utils as vmw_utils
|
|
from vmware_nsx.db import db as nsx_db
|
|
from vmware_nsx import nsx_cluster
|
|
from vmware_nsx.nsxlib.mh import switch as switchlib
|
|
|
|
LOG = log.getLogger(__name__)
|
|
|
|
|
|
def get_nsx_switch_ids(session, cluster, neutron_network_id):
|
|
"""Return the NSX switch id for a given neutron network.
|
|
|
|
First lookup for mappings in Neutron database. If no mapping is
|
|
found, query the NSX backend and add the mappings.
|
|
"""
|
|
nsx_switch_ids = nsx_db.get_nsx_switch_ids(
|
|
session, neutron_network_id)
|
|
if not nsx_switch_ids:
|
|
# Find logical switches from backend.
|
|
# This is a rather expensive query, but it won't be executed
|
|
# more than once for each network in Neutron's lifetime
|
|
nsx_switches = switchlib.get_lswitches(cluster, neutron_network_id)
|
|
if not nsx_switches:
|
|
LOG.warning("Unable to find NSX switches for Neutron network "
|
|
"%s", neutron_network_id)
|
|
return
|
|
nsx_switch_ids = []
|
|
with session.begin(subtransactions=True):
|
|
for nsx_switch in nsx_switches:
|
|
nsx_switch_id = nsx_switch['uuid']
|
|
nsx_switch_ids.append(nsx_switch_id)
|
|
# Create DB mapping
|
|
nsx_db.add_neutron_nsx_network_mapping(
|
|
session,
|
|
neutron_network_id,
|
|
nsx_switch_id)
|
|
return nsx_switch_ids
|
|
|
|
|
|
def get_nsx_switch_and_port_id(session, cluster, neutron_port_id):
|
|
"""Return the NSX switch and port uuids for a given neutron port.
|
|
|
|
First, look up the Neutron database. If not found, execute
|
|
a query on NSX platform as the mapping might be missing because
|
|
the port was created before upgrading to grizzly.
|
|
|
|
This routine also retrieves the identifier of the logical switch in
|
|
the backend where the port is plugged. Prior to Icehouse this
|
|
information was not available in the Neutron Database. For dealing
|
|
with pre-existing records, this routine will query the backend
|
|
for retrieving the correct switch identifier.
|
|
|
|
As of Icehouse release it is not indeed anymore possible to assume
|
|
the backend logical switch identifier is equal to the neutron
|
|
network identifier.
|
|
"""
|
|
nsx_switch_id, nsx_port_id = nsx_db.get_nsx_switch_and_port_id(
|
|
session, neutron_port_id)
|
|
if not nsx_switch_id:
|
|
# Find logical switch for port from backend
|
|
# This is a rather expensive query, but it won't be executed
|
|
# more than once for each port in Neutron's lifetime
|
|
nsx_ports = switchlib.query_lswitch_lports(
|
|
cluster, '*', relations='LogicalSwitchConfig',
|
|
filters={'tag': neutron_port_id,
|
|
'tag_scope': 'q_port_id'})
|
|
# Only one result expected
|
|
# NOTE(salv-orlando): Not handling the case where more than one
|
|
# port is found with the same neutron port tag
|
|
if not nsx_ports:
|
|
LOG.warning("Unable to find NSX port for Neutron port %s",
|
|
neutron_port_id)
|
|
# This method is supposed to return a tuple
|
|
return None, None
|
|
nsx_port = nsx_ports[0]
|
|
nsx_switch_id = (nsx_port['_relations']
|
|
['LogicalSwitchConfig']['uuid'])
|
|
if nsx_port_id:
|
|
# Mapping already exists. Delete before recreating
|
|
nsx_db.delete_neutron_nsx_port_mapping(
|
|
session, neutron_port_id)
|
|
else:
|
|
nsx_port_id = nsx_port['uuid']
|
|
# (re)Create DB mapping
|
|
nsx_db.add_neutron_nsx_port_mapping(
|
|
session, neutron_port_id,
|
|
nsx_switch_id, nsx_port_id)
|
|
return nsx_switch_id, nsx_port_id
|
|
|
|
|
|
def create_nsx_cluster(cluster_opts, concurrent_connections, gen_timeout):
|
|
cluster = nsx_cluster.NSXCluster(**cluster_opts)
|
|
|
|
def _ctrl_split(x, y):
|
|
return (x, int(y), True)
|
|
|
|
api_providers = [_ctrl_split(*ctrl.split(':'))
|
|
for ctrl in cluster.nsx_controllers]
|
|
cluster.api_client = client.NsxApiClient(
|
|
api_providers, cluster.nsx_user, cluster.nsx_password,
|
|
http_timeout=cluster.http_timeout,
|
|
retries=cluster.retries,
|
|
redirects=cluster.redirects,
|
|
concurrent_connections=concurrent_connections,
|
|
gen_timeout=gen_timeout)
|
|
return cluster
|
|
|
|
|
|
def _convert_bindings_to_nsx_transport_zones(bindings):
|
|
nsx_transport_zones_config = []
|
|
for binding in bindings:
|
|
transport_entry = {}
|
|
if binding.binding_type in [vmw_utils.NetworkTypes.FLAT,
|
|
vmw_utils.NetworkTypes.VLAN]:
|
|
transport_entry['transport_type'] = (
|
|
vmw_utils.NetworkTypes.BRIDGE)
|
|
transport_entry['binding_config'] = {}
|
|
vlan_id = binding.vlan_id
|
|
if vlan_id:
|
|
transport_entry['binding_config'] = (
|
|
{'vlan_translation': [{'transport': vlan_id}]})
|
|
else:
|
|
transport_entry['transport_type'] = binding.binding_type
|
|
transport_entry['zone_uuid'] = binding.phy_uuid
|
|
nsx_transport_zones_config.append(transport_entry)
|
|
return nsx_transport_zones_config
|
|
|
|
|
|
def _convert_segments_to_nsx_transport_zones(segments, default_tz_uuid):
|
|
nsx_transport_zones_config = []
|
|
for transport_zone in segments:
|
|
for value in [pnet.NETWORK_TYPE, pnet.PHYSICAL_NETWORK,
|
|
pnet.SEGMENTATION_ID]:
|
|
if transport_zone.get(value) == constants.ATTR_NOT_SPECIFIED:
|
|
transport_zone[value] = None
|
|
|
|
transport_entry = {}
|
|
transport_type = transport_zone.get(pnet.NETWORK_TYPE)
|
|
if transport_type in [vmw_utils.NetworkTypes.FLAT,
|
|
vmw_utils.NetworkTypes.VLAN]:
|
|
transport_entry['transport_type'] = (
|
|
vmw_utils.NetworkTypes.BRIDGE)
|
|
transport_entry['binding_config'] = {}
|
|
vlan_id = transport_zone.get(pnet.SEGMENTATION_ID)
|
|
if vlan_id:
|
|
transport_entry['binding_config'] = (
|
|
{'vlan_translation': [{'transport': vlan_id}]})
|
|
else:
|
|
transport_entry['transport_type'] = transport_type
|
|
transport_entry['zone_uuid'] = (
|
|
transport_zone[pnet.PHYSICAL_NETWORK] or default_tz_uuid)
|
|
nsx_transport_zones_config.append(transport_entry)
|
|
return nsx_transport_zones_config
|
|
|
|
|
|
def convert_to_nsx_transport_zones(
|
|
default_tz_uuid, network=None, bindings=None,
|
|
default_transport_type=None):
|
|
|
|
# Convert fields from provider request to nsx format
|
|
if (network and not validators.is_attr_set(
|
|
network.get(mpnet_apidef.SEGMENTS))):
|
|
return [{"zone_uuid": default_tz_uuid,
|
|
"transport_type": default_transport_type}]
|
|
|
|
# Convert fields from db to nsx format
|
|
if bindings:
|
|
return _convert_bindings_to_nsx_transport_zones(bindings)
|
|
|
|
# If we end up here we need to convert multiprovider segments into nsx
|
|
# transport zone configurations
|
|
return _convert_segments_to_nsx_transport_zones(
|
|
network.get(mpnet_apidef.SEGMENTS), default_tz_uuid)
|