NSX TVD: V, T and simple DVS Coexist in the same plugin
Introduce a plugin that can work with all of the VC and NSX offerings under the same umbrella of a single plugin. Co-Authored-By: Adit Sarfaty <asarfaty@vmware.com> Change-Id: I0449d64e3cf79b7a3a846dacba95e8854d53bdf8
This commit is contained in:
parent
315e0befe0
commit
792a6a0103
@ -33,7 +33,6 @@ function nsxv_configure_service {
|
||||
if [[ "$NSX_L2GW_DRIVER" != "" ]]; then
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT nsx_l2gw_driver $NSX_L2GW_DRIVER
|
||||
fi
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT nsx_extension_drivers vmware_nsxv_dns
|
||||
_nsxv_ini_set password "$NSXV_PASSWORD"
|
||||
_nsxv_ini_set user "$NSXV_USER"
|
||||
_nsxv_ini_set vdn_scope_id "$NSXV_VDN_SCOPE_ID"
|
||||
@ -104,7 +103,6 @@ function nsxv3_configure_service {
|
||||
if [[ "$NSX_L2GW_DRIVER" != "" ]]; then
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT nsx_l2gw_driver $NSX_L2GW_DRIVER
|
||||
fi
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT nsx_extension_drivers vmware_nsxv3_dns
|
||||
_nsxv3_ini_set nsx_api_user $NSX_USER
|
||||
_nsxv3_ini_set nsx_api_password $NSX_PASSWORD
|
||||
_nsxv3_ini_set retries $NSX_RETRIES
|
||||
|
253
devstack/lib/vmware_nsx_tvd
Normal file
253
devstack/lib/vmware_nsx_tvd
Normal file
@ -0,0 +1,253 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Copyright 2015 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.
|
||||
|
||||
|
||||
# Neutron VMware NSX plugin
|
||||
# -------------------------
|
||||
|
||||
# Settings previously defined in devstack:lib/neutron-legacy
|
||||
NEUTRON_CONF_DIR=/etc/neutron
|
||||
export NEUTRON_TEST_CONFIG_FILE=${NEUTRON_TEST_CONFIG_FILE:-"$NEUTRON_CONF_DIR/debug.ini"}
|
||||
Q_DHCP_CONF_FILE=$NEUTRON_CONF_DIR/dhcp_agent.ini
|
||||
|
||||
# The interface which has connectivity to the NSX Gateway uplink
|
||||
NSX_GATEWAY_NETWORK_INTERFACE=${NSX_GATEWAY_NETWORK_INTERFACE:-}
|
||||
|
||||
# Override default 'True' in devstack:lib/neutron_plugins/services/l3
|
||||
Q_USE_PROVIDERNET_FOR_PUBLIC=False
|
||||
|
||||
# Native support from platform
|
||||
NATIVE_DHCP_METADATA=${NATIVE_DHCP_METADATA:-True}
|
||||
NATIVE_METADATA_ROUTE=${NATIVE_METADATA_ROUTE:-169.254.169.254/31}
|
||||
METADATA_PROXY_SHARED_SECRET=${METADATA_PROXY_SHARED_SECRET:-}
|
||||
|
||||
# Default AZ
|
||||
NSX_DEFAULT_AZ=${NSX_DEFAULT_AZ:-defaultv3}
|
||||
|
||||
# Save trace setting
|
||||
NSX_XTRACE=$(set +o | grep xtrace)
|
||||
set +o xtrace
|
||||
|
||||
# File to store client certificate and PK
|
||||
CLIENT_CERT_FILE=${DEST}/data/neutron/client.pem
|
||||
|
||||
source $TOP_DIR/lib/neutron_plugins/ovs_base
|
||||
dir=${GITDIR['vmware-nsx']}/devstack
|
||||
source $dir/lib/nsx_common
|
||||
|
||||
|
||||
function _version { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
|
||||
|
||||
function _ovsdb_connection {
|
||||
managers=(${NSX_MANAGER//,/ })
|
||||
NSX_MGR_IP=${managers[0]}
|
||||
NSX_VER=$(curl -1 -s -k -u "$NSX_USER:$NSX_PASSWORD" -H 'Accept: application/json' https://$NSX_MGR_IP/api/v1/node | python -c 'import sys, json; print json.load(sys.stdin)["node_version"][:5]')
|
||||
if [ $(_version $NSX_VER) -ge $(_version 1.1.0) ]; then
|
||||
echo "unix:/var/run/vmware/nsx-agent/nsxagent_ovsdb.sock"
|
||||
else
|
||||
echo "tcp:127.0.0.1:6632"
|
||||
fi
|
||||
}
|
||||
|
||||
function setup_integration_bridge {
|
||||
die_if_not_set $LINENO NSX_MANAGER "NSX_MANAGER has not been set!"
|
||||
die_if_not_set $LINENO NSX_USER "NSX_USER has not been set!"
|
||||
die_if_not_set $LINENO NSX_PASSWORD "NSX_PASSWORD has not been set!"
|
||||
# Ensure that the OVS params are set for the OVS utils
|
||||
iniset $NEUTRON_CONF DEFAULT ovs_integration_bridge $OVS_BRIDGE
|
||||
iniset $NEUTRON_CONF OVS ovsdb_connection $(_ovsdb_connection)
|
||||
iniset $NEUTRON_CONF OVS ovsdb_interface vsctl
|
||||
_neutron_ovs_base_setup_bridge $OVS_BRIDGE
|
||||
sudo ovs-vsctl set bridge $OVS_BRIDGE external_ids:bridge-id=nsx-managed
|
||||
sudo ovs-vsctl set-manager $(_ovsdb_connection)
|
||||
}
|
||||
|
||||
function is_neutron_ovs_base_plugin {
|
||||
# This allows the deployer to decide whether devstack should install OVS.
|
||||
# By default, we install OVS, to change this behavior add "OVS_BASE=1" to your localrc file.
|
||||
# Note: Any KVM compute must have OVS installed on it.
|
||||
return ${OVS_BASE:-0}
|
||||
}
|
||||
|
||||
function neutron_plugin_create_nova_conf {
|
||||
if [[ "$VIRT_DRIVER" != 'vsphere' ]]; then
|
||||
# if n-cpu or octavia is enabled, then setup integration bridge
|
||||
if is_service_enabled n-cpu || is_service_enabled octavia ; then
|
||||
setup_integration_bridge
|
||||
if is_service_enabled n-cpu ; then
|
||||
iniset $NOVA_CONF neutron ovs_bridge $OVS_BRIDGE
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
# if n-api is enabled, then setup the metadata_proxy_shared_secret
|
||||
if is_service_enabled n-api; then
|
||||
iniset $NOVA_CONF neutron service_metadata_proxy True
|
||||
if [[ "$NATIVE_DHCP_METADATA" == "True" ]]; then
|
||||
iniset $NOVA_CONF neutron metadata_proxy_shared_secret $METADATA_PROXY_SHARED_SECRET
|
||||
if [[ "$METADATA_PROXY_USE_HTTPS" == "True" ]]; then
|
||||
iniset $NOVA_CONF DEFAULT enabled_ssl_apis metadata
|
||||
if [[ "$METADATA_PROXY_CERT_FILE" != "" ]]; then
|
||||
iniset $NOVA_CONF wsgi ssl_cert_file $METADATA_PROXY_CERT_FILE
|
||||
fi
|
||||
if [[ "$METADATA_PROXY_PRIV_KEY_FILE" != "" ]]; then
|
||||
iniset $NOVA_CONF wsgi ssl_key_file $METADATA_PROXY_PRIV_KEY_FILE
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function neutron_plugin_install_agent_packages {
|
||||
# VMware NSX Plugin does not run q-agt, but it currently needs dhcp and metadata agents
|
||||
_neutron_ovs_base_install_agent_packages
|
||||
}
|
||||
|
||||
function neutron_plugin_configure_common {
|
||||
Q_PLUGIN_CONF_PATH=etc/neutron/plugins/vmware
|
||||
Q_PLUGIN_CONF_FILENAME=nsx.ini
|
||||
Q_PLUGIN_SRC_CONF_PATH=vmware-nsx/etc
|
||||
VMWARE_NSX_DIR=vmware-nsx
|
||||
# Uses oslo config generator to generate sample configuration file
|
||||
(cd $DEST/$VMWARE_NSX_DIR && exec ./tools/generate_config_file_samples.sh)
|
||||
mkdir -p /$Q_PLUGIN_CONF_PATH
|
||||
cp $DEST/$Q_PLUGIN_SRC_CONF_PATH/nsx.ini.sample /$Q_PLUGIN_CONF_PATH/$Q_PLUGIN_CONF_FILENAME
|
||||
sudo install -d -o $STACK_USER $NEUTRON_CONF_DIR/policy.d
|
||||
cp -vr $DEST/$Q_PLUGIN_SRC_CONF_PATH/policy.d $NEUTRON_CONF_DIR/policy.d
|
||||
Q_PLUGIN_CLASS="vmware_nsxtvd"
|
||||
}
|
||||
|
||||
function neutron_plugin_configure_debug_command {
|
||||
sudo ovs-vsctl --no-wait -- --may-exist add-br $PUBLIC_BRIDGE
|
||||
iniset $NEUTRON_TEST_CONFIG_FILE DEFAULT external_network_bridge "$PUBLIC_BRIDGE"
|
||||
}
|
||||
|
||||
function neutron_plugin_configure_dhcp_agent {
|
||||
setup_integration_bridge
|
||||
iniset $Q_DHCP_CONF_FILE DEFAULT enable_isolated_metadata True
|
||||
iniset $Q_DHCP_CONF_FILE DEFAULT enable_metadata_network True
|
||||
iniset $Q_DHCP_CONF_FILE DEFAULT ovs_use_veth True
|
||||
iniset $Q_DHCP_CONF_FILE DEFAULT ovs_integration_bridge $OVS_BRIDGE
|
||||
iniset $Q_DHCP_CONF_FILE OVS ovsdb_connection $(_ovsdb_connection)
|
||||
iniset $Q_DHCP_CONF_FILE OVS ovsdb_interface vsctl
|
||||
}
|
||||
|
||||
function neutron_plugin_configure_l3_agent {
|
||||
# VMware NSX plugin does not run L3 agent
|
||||
die $LINENO "q-l3 should not be executed with VMware NSX plugin!"
|
||||
}
|
||||
|
||||
function neutron_plugin_configure_plugin_agent {
|
||||
# VMware NSX plugin does not run L2 agent
|
||||
die $LINENO "q-agt must not be executed with VMware NSX plugin!"
|
||||
}
|
||||
|
||||
function neutron_plugin_configure_service {
|
||||
nsxv3_configure_service
|
||||
nsxv_configure_service
|
||||
iniset /$Q_PLUGIN_CONF_FILE nsx_tvd nsx_v_extension_drivers vmware_nsxv_dns
|
||||
iniset /$Q_PLUGIN_CONF_FILE nsx_tvd nsx_v3_extension_drivers vmware_nsxv3_dns
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT default_availability_zones $NSX_DEFAULT_AZ
|
||||
}
|
||||
|
||||
function neutron_plugin_setup_interface_driver {
|
||||
local conf_file=$1
|
||||
iniset $conf_file DEFAULT interface_driver neutron.agent.linux.interface.OVSInterfaceDriver
|
||||
}
|
||||
|
||||
function neutron_plugin_check_adv_test_requirements {
|
||||
is_service_enabled q-dhcp && return 0
|
||||
}
|
||||
|
||||
|
||||
function init_vmware_nsx_tvd {
|
||||
if (is_service_enabled q-svc || is_service_enabled neutron-api) && [[ "$NATIVE_DHCP_METADATA" == "True" ]]; then
|
||||
if ! is_set DHCP_PROFILE_UUID; then
|
||||
die $LINENO "DHCP profile needs to be configured!"
|
||||
fi
|
||||
if ! is_set METADATA_PROXY_UUID; then
|
||||
die $LINENO "Metadata proxy needs to be configured!"
|
||||
fi
|
||||
if is_service_enabled q-dhcp q-meta; then
|
||||
die $LINENO "Native support does not require DHCP and Metadata agents!"
|
||||
fi
|
||||
fi
|
||||
# Generate client certificate
|
||||
if [[ "$NSX_USE_CLIENT_CERT_AUTH" == "True" ]]; then
|
||||
nsxadmin -o generate -r certificate
|
||||
fi
|
||||
if ! is_set NSX_GATEWAY_NETWORK_INTERFACE; then
|
||||
echo "NSX_GATEWAY_NETWORK_INTERFACE not set not configuring routes"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! is_set NSX_GATEWAY_NETWORK_CIDR; then
|
||||
NSX_GATEWAY_NETWORK_CIDR=$PUBLIC_NETWORK_GATEWAY/${FLOATING_RANGE#*/}
|
||||
echo "The IP address to set on $PUBLIC_BRIDGE was not specified. "
|
||||
echo "Defaulting to $NSX_GATEWAY_NETWORK_CIDR"
|
||||
fi
|
||||
# Make sure the interface is up, but not configured
|
||||
sudo ip link set $NSX_GATEWAY_NETWORK_INTERFACE up
|
||||
# Save and then flush the IP addresses on the interface
|
||||
addresses=$(ip addr show dev $NSX_GATEWAY_NETWORK_INTERFACE | grep inet | awk {'print $2'})
|
||||
sudo ip addr flush $NSX_GATEWAY_NETWORK_INTERFACE
|
||||
# Use the PUBLIC Bridge to route traffic to the NSX gateway
|
||||
# NOTE(armando-migliaccio): if running in a nested environment this will work
|
||||
# only with mac learning enabled, portsecurity and security profiles disabled
|
||||
# The public bridge might not exist for the NSX plugin if Q_USE_DEBUG_COMMAND is off
|
||||
# Try to create it anyway
|
||||
sudo ovs-vsctl --may-exist add-br $PUBLIC_BRIDGE
|
||||
sudo ovs-vsctl --may-exist add-port $PUBLIC_BRIDGE $NSX_GATEWAY_NETWORK_INTERFACE
|
||||
# Flush all existing addresses on public bridge
|
||||
sudo ip addr flush dev $PUBLIC_BRIDGE
|
||||
nsx_gw_net_if_mac=$(ip link show $NSX_GATEWAY_NETWORK_INTERFACE | awk '/ether/ {print $2}')
|
||||
sudo ip link set address $nsx_gw_net_if_mac dev $PUBLIC_BRIDGE
|
||||
for address in $addresses; do
|
||||
sudo ip addr add dev $PUBLIC_BRIDGE $address
|
||||
done
|
||||
sudo ip addr add dev $PUBLIC_BRIDGE $NSX_GATEWAY_NETWORK_CIDR
|
||||
sudo ip link set $PUBLIC_BRIDGE up
|
||||
}
|
||||
|
||||
function stop_vmware_nsx_tvd {
|
||||
# Clean client certificate if exists
|
||||
nsxadmin -o clean -r certificate
|
||||
|
||||
if ! is_set NSX_GATEWAY_NETWORK_INTERFACE; then
|
||||
echo "NSX_GATEWAY_NETWORK_INTERFACE was not configured."
|
||||
return
|
||||
fi
|
||||
|
||||
if ! is_set NSX_GATEWAY_NETWORK_CIDR; then
|
||||
NSX_GATEWAY_NETWORK_CIDR=$PUBLIC_NETWORK_GATEWAY/${FLOATING_RANGE#*/}
|
||||
echo "The IP address expected on $PUBLIC_BRIDGE was not specified. "
|
||||
echo "Defaulting to "$NSX_GATEWAY_NETWORK_CIDR
|
||||
fi
|
||||
sudo ip addr del $NSX_GATEWAY_NETWORK_CIDR dev $PUBLIC_BRIDGE
|
||||
# Save and then flush remaining addresses on the interface
|
||||
addresses=$(ip addr show dev $PUBLIC_BRIDGE | grep inet | awk {'print $2'})
|
||||
sudo ip addr flush $PUBLIC_BRIDGE
|
||||
# Try to detach physical interface from PUBLIC_BRIDGE
|
||||
sudo ovs-vsctl del-port $NSX_GATEWAY_NETWORK_INTERFACE
|
||||
# Restore addresses on NSX_GATEWAY_NETWORK_INTERFACE
|
||||
for address in $addresses; do
|
||||
sudo ip addr add dev $NSX_GATEWAY_NETWORK_INTERFACE $address
|
||||
done
|
||||
}
|
||||
|
||||
# Restore xtrace
|
||||
$NSX_XTRACE
|
@ -84,6 +84,7 @@ function neutron_plugin_configure_plugin_agent {
|
||||
|
||||
function neutron_plugin_configure_service {
|
||||
nsxv_configure_service
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT nsx_extension_drivers vmware_nsxv_dns
|
||||
}
|
||||
|
||||
function neutron_plugin_setup_interface_driver {
|
||||
|
@ -155,6 +155,7 @@ function neutron_plugin_configure_plugin_agent {
|
||||
|
||||
function neutron_plugin_configure_service {
|
||||
nsxv3_configure_service
|
||||
iniset /$Q_PLUGIN_CONF_FILE DEFAULT nsx_extension_drivers vmware_nsxv3_dns
|
||||
}
|
||||
|
||||
function neutron_plugin_setup_interface_driver {
|
||||
|
@ -71,6 +71,28 @@ elif [[ $Q_PLUGIN == 'vmware_nsx_v3' ]]; then
|
||||
python $dir/tools/nsxv3_cleanup.py --mgr-ip $NSX_MANAGER --user $NSX_USER --password $NSX_PASSWORD
|
||||
fi
|
||||
fi
|
||||
elif [[ $Q_PLUGIN == 'vmware_nsx_tvd' ]]; then
|
||||
source $dir/lib/vmware_nsx_tvd
|
||||
if [[ "$1" == "stack" && "$2" == "post-config" ]]; then
|
||||
init_vmware_nsx_tvd
|
||||
elif [[ "$1" == "unstack" ]]; then
|
||||
db_connection=$(iniget $NEUTRON_CONF database connection)
|
||||
stop_vmware_nsx_v3
|
||||
# only clean up when q-svc (legacy support) or neutron-api is enabled
|
||||
if is_service_enabled q-svc || is_service_enabled neutron-api; then
|
||||
NSX_MANAGER=${NSX_MANAGERS:-$NSX_MANAGER}
|
||||
IFS=','
|
||||
NSX_MANAGER=($NSX_MANAGER)
|
||||
unset IFS
|
||||
python $dir/tools/nsxv3_cleanup.py --mgr-ip $NSX_MANAGER --user $NSX_USER --password $NSX_PASSWORD --db-connection $db_connection
|
||||
python $dir/tools/nsxv_cleanup.py --vsm-ip ${NSXV_MANAGER_URI/https:\/\/} --user $NSXV_USER --password $NSXV_PASSWORD --db-connection $db_connection
|
||||
fi
|
||||
elif [[ "$1" == 'clean' ]]; then
|
||||
if is_service_enabled q-svc || is_service_enabled neutron-api; then
|
||||
python $dir/tools/nsxv3_cleanup.py --mgr-ip $NSX_MANAGER --user $NSX_USER --password $NSX_PASSWORD
|
||||
python $dir/tools/nsxv_cleanup.py --vsm-ip ${NSXV_MANAGER_URI/https:\/\/} --user $NSXV_USER --password $NSXV_PASSWORD
|
||||
fi
|
||||
fi
|
||||
elif [[ $Q_PLUGIN == 'vmware_dvs' ]]; then
|
||||
source $dir/lib/vmware_dvs
|
||||
fi
|
||||
|
@ -33,6 +33,7 @@ neutron.core_plugins =
|
||||
vmware_nsxv = vmware_nsx.plugin:NsxVPlugin
|
||||
vmware_nsxv3 = vmware_nsx.plugin:NsxV3Plugin
|
||||
vmware_dvs = vmware_nsx.plugin:NsxDvsPlugin
|
||||
vmware_nsxtvd = vmware_nsx.plugin:NsxTVDPlugin
|
||||
firewall_drivers =
|
||||
vmware_nsxv_edge = vmware_nsx.services.fwaas.nsx_v.edge_fwaas_driver:EdgeFwaasDriver
|
||||
vmware_nsxv3_edge = vmware_nsx.services.fwaas.nsx_v3.edge_fwaas_driver_v1:EdgeFwaasV3DriverV1
|
||||
@ -68,6 +69,9 @@ openstack.nsxclient.v2 =
|
||||
security_group_set = vmware_nsx.osc.v2.security_group:NsxSetSecurityGroup
|
||||
subnet_create = vmware_nsx.osc.v2.subnet:NsxCreateSubnet
|
||||
subnet_set = vmware_nsx.osc.v2.subnet:NsxSetSubnet
|
||||
project_plugin_create = vmware_nsx.osc.v2.project_plugin_map:CreateProjectPluginMap
|
||||
project_plugin_show = vmware_nsx.osc.v2.project_plugin_map:ShowProjectPluginMap
|
||||
project_plugin_list = vmware_nsx.osc.v2.project_plugin_map:ListProjectPluginMap
|
||||
|
||||
[build_sphinx]
|
||||
source-dir = doc/source
|
||||
|
@ -78,7 +78,7 @@ class ConfiguredAvailabilityZones(object):
|
||||
|
||||
default_name = DEFAULT_NAME
|
||||
|
||||
def __init__(self, az_conf, az_class):
|
||||
def __init__(self, az_conf, az_class, validate_default=True):
|
||||
self.availability_zones = {}
|
||||
|
||||
# Add the configured availability zones
|
||||
@ -100,12 +100,17 @@ class ConfiguredAvailabilityZones(object):
|
||||
reason=_("The NSX plugin supports only 1 default AZ"))
|
||||
default_az_name = cfg.CONF.default_availability_zones[0]
|
||||
if (default_az_name not in self.availability_zones):
|
||||
raise nsx_exc.NsxInvalidConfiguration(
|
||||
opt_name="default_availability_zones",
|
||||
opt_value=cfg.CONF.default_availability_zones,
|
||||
reason=_("The default AZ is not defined in the NSX "
|
||||
"plugin"))
|
||||
self._default_az = self.availability_zones[default_az_name]
|
||||
if validate_default:
|
||||
raise nsx_exc.NsxInvalidConfiguration(
|
||||
opt_name="default_availability_zones",
|
||||
opt_value=cfg.CONF.default_availability_zones,
|
||||
reason=_("The default AZ is not defined in the NSX "
|
||||
"plugin"))
|
||||
else:
|
||||
self._default_az = self.availability_zones[
|
||||
self.default_name]
|
||||
else:
|
||||
self._default_az = self.availability_zones[default_az_name]
|
||||
else:
|
||||
self._default_az = self.availability_zones[self.default_name]
|
||||
|
||||
|
@ -813,12 +813,26 @@ nsxv3_az_opts = [
|
||||
"on router ports.")),
|
||||
]
|
||||
|
||||
nsx_tvd_opts = [
|
||||
cfg.ListOpt('nsx_v_extension_drivers',
|
||||
default=[],
|
||||
help=_("An ordered list of NSX-V extension driver "
|
||||
"entrypoints to be loaded from the "
|
||||
"vmware_nsx.extension_drivers namespace.")),
|
||||
cfg.ListOpt('nsx_v3_extension_drivers',
|
||||
default=[],
|
||||
help=_("An ordered list of NSX-T extension driver "
|
||||
"entrypoints to be loaded from the "
|
||||
"vmware_nsx.extension_drivers namespace.")),
|
||||
]
|
||||
|
||||
# Register the configuration options
|
||||
cfg.CONF.register_opts(connection_opts)
|
||||
cfg.CONF.register_opts(cluster_opts)
|
||||
cfg.CONF.register_opts(nsx_common_opts)
|
||||
cfg.CONF.register_opts(nsx_v3_opts, group="nsx_v3")
|
||||
cfg.CONF.register_opts(nsxv_opts, group="nsxv")
|
||||
cfg.CONF.register_opts(nsx_tvd_opts, group="nsx_tvd")
|
||||
cfg.CONF.register_opts(base_opts, group="NSX")
|
||||
cfg.CONF.register_opts(sync_opts, group="NSX_SYNC")
|
||||
|
||||
@ -891,3 +905,9 @@ def validate_nsxv_config_options():
|
||||
error = _("dvs host/vcenter credentials must be defined to use "
|
||||
"dvs features")
|
||||
raise nsx_exc.NsxPluginException(err_msg=error)
|
||||
|
||||
|
||||
def validate_nsx_config_options():
|
||||
if cfg.CONF.nsx_extension_drivers:
|
||||
error = _("nsx_extension_drivers should not be configured!")
|
||||
raise nsx_exc.NsxPluginException(err_msg=error)
|
||||
|
@ -24,15 +24,18 @@ LOG = log.getLogger(__name__)
|
||||
class ExtensionManager(stevedore.named.NamedExtensionManager):
|
||||
"""Manage extension drivers using drivers."""
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, extension_drivers=None):
|
||||
# Ordered list of extension drivers, defining
|
||||
# the order in which the drivers are called.
|
||||
self.ordered_ext_drivers = []
|
||||
|
||||
if extension_drivers is None:
|
||||
extension_drivers = cfg.CONF.nsx_extension_drivers
|
||||
|
||||
LOG.info("Configured extension driver names: %s",
|
||||
cfg.CONF.nsx_extension_drivers)
|
||||
extension_drivers)
|
||||
super(ExtensionManager, self).__init__('vmware_nsx.extension_drivers',
|
||||
cfg.CONF.nsx_extension_drivers,
|
||||
extension_drivers,
|
||||
invoke_on_load=True,
|
||||
name_order=True)
|
||||
LOG.info("Loaded extension driver names: %s", self.names())
|
||||
|
@ -20,6 +20,7 @@ from sqlalchemy.orm import exc
|
||||
from oslo_db import exception as db_exc
|
||||
from oslo_log import log as logging
|
||||
from oslo_utils import excutils
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
import neutron.db.api as db
|
||||
|
||||
@ -289,16 +290,20 @@ def get_neutron_from_nsx_router_id(session, nsx_router_id):
|
||||
LOG.debug("Couldn't find router with nsx id %s", nsx_router_id)
|
||||
|
||||
|
||||
def get_nsx_security_group_id(session, neutron_id):
|
||||
def get_nsx_security_group_id(session, neutron_id, moref=False):
|
||||
"""Return the id of a security group in the NSX backend.
|
||||
|
||||
Note: security groups are called 'security profiles' in NSX
|
||||
"""
|
||||
try:
|
||||
mapping = (session.query(nsx_models.NeutronNsxSecurityGroupMapping).
|
||||
filter_by(neutron_id=neutron_id).
|
||||
one())
|
||||
return mapping['nsx_id']
|
||||
mappings = (session.query(nsx_models.NeutronNsxSecurityGroupMapping).
|
||||
filter_by(neutron_id=neutron_id).
|
||||
all())
|
||||
for mapping in mappings:
|
||||
if moref and not uuidutils.is_uuid_like(mapping['nsx_id']):
|
||||
return mapping['nsx_id']
|
||||
if not moref and uuidutils.is_uuid_like(mapping['nsx_id']):
|
||||
return mapping['nsx_id']
|
||||
except exc.NoResultFound:
|
||||
LOG.debug("NSX identifiers for neutron security group %s not yet "
|
||||
"stored in Neutron DB", neutron_id)
|
||||
@ -437,14 +442,29 @@ def save_sg_mappings(context, sg_id, nsgroup_id, section_id):
|
||||
nsx_id=nsgroup_id))
|
||||
|
||||
|
||||
def get_sg_mappings(session, sg_id):
|
||||
nsgroup_mapping = session.query(
|
||||
def get_sg_mappings(session, sg_id, moref=False):
|
||||
nsgroup_mappings = session.query(
|
||||
nsx_models.NeutronNsxSecurityGroupMapping
|
||||
).filter_by(neutron_id=sg_id).one()
|
||||
section_mapping = session.query(
|
||||
).filter_by(neutron_id=sg_id).all()
|
||||
nsgroup_mapping = section_mapping = None
|
||||
for mapping in nsgroup_mappings:
|
||||
if moref and not uuidutils.is_uuid_like(mapping['nsx_id']):
|
||||
nsgroup_mapping = mapping['nsx_id']
|
||||
break
|
||||
if not moref and uuidutils.is_uuid_like(mapping['nsx_id']):
|
||||
nsgroup_mapping = mapping['nsx_id']
|
||||
break
|
||||
section_mappings = session.query(
|
||||
nsx_models.NeutronNsxFirewallSectionMapping
|
||||
).filter_by(neutron_id=sg_id).one()
|
||||
return nsgroup_mapping.nsx_id, section_mapping.nsx_id
|
||||
).filter_by(neutron_id=sg_id).all()
|
||||
for mapping in section_mappings:
|
||||
if moref and not uuidutils.is_uuid_like(mapping['nsx_id']):
|
||||
section_mapping = mapping['nsx_id']
|
||||
break
|
||||
if not moref and uuidutils.is_uuid_like(mapping['nsx_id']):
|
||||
section_mapping = mapping['nsx_id']
|
||||
break
|
||||
return nsgroup_mapping, section_mapping
|
||||
|
||||
|
||||
def get_sg_rule_mapping(session, rule_id):
|
||||
@ -652,3 +672,23 @@ def get_nsx_lbaas_l7policy_binding(session, l7policy_id):
|
||||
def delete_nsx_lbaas_l7policy_binding(session, l7policy_id):
|
||||
return (session.query(nsx_models.NsxLbaasL7Policy).
|
||||
filter_by(l7policy_id=l7policy_id).delete())
|
||||
|
||||
|
||||
def add_project_plugin_mapping(session, project, plugin):
|
||||
with session.begin(subtransactions=True):
|
||||
binding = nsx_models.NsxProjectPluginMapping(
|
||||
project=project, plugin=plugin)
|
||||
session.add(binding)
|
||||
return binding
|
||||
|
||||
|
||||
def get_project_plugin_mapping(session, project):
|
||||
try:
|
||||
return session.query(nsx_models.NsxProjectPluginMapping).filter_by(
|
||||
project=project).one()
|
||||
except exc.NoResultFound:
|
||||
return
|
||||
|
||||
|
||||
def get_project_plugin_mappings(session):
|
||||
return session.query(nsx_models.NsxProjectPluginMapping).all()
|
||||
|
@ -1 +1 @@
|
||||
ea7a72ab9643
|
||||
9799427fc0e1
|
||||
|
@ -0,0 +1,41 @@
|
||||
# Copyright 2017 VMware, Inc.
|
||||
#
|
||||
# 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.
|
||||
|
||||
"""nsx map project to plugin
|
||||
|
||||
Revision ID: 9799427fc0e1
|
||||
Revises: ea7a72ab9643
|
||||
Create Date: 2017-06-12 16:59:48.021909
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '9799427fc0e1'
|
||||
down_revision = 'ea7a72ab9643'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
|
||||
plugin_type_enum = sa.Enum('dvs', 'nsx-v', 'nsx-t',
|
||||
name='nsx_plugin_type')
|
||||
|
||||
|
||||
def upgrade():
|
||||
op.create_table(
|
||||
'nsx_project_plugin_mappings',
|
||||
sa.Column('project', sa.String(36), nullable=False),
|
||||
sa.Column('plugin', plugin_type_enum, nullable=False),
|
||||
sa.Column('created_at', sa.DateTime(), nullable=True),
|
||||
sa.Column('updated_at', sa.DateTime(), nullable=True),
|
||||
sa.PrimaryKeyConstraint('project'))
|
@ -481,3 +481,10 @@ class NsxLbaasL7Policy(model_base.BASEV2, models.TimestampMixin):
|
||||
primary_key=True)
|
||||
lb_rule_id = sa.Column(sa.String(36), nullable=False)
|
||||
lb_vs_id = sa.Column(sa.String(36), nullable=False)
|
||||
|
||||
|
||||
class NsxProjectPluginMapping(model_base.BASEV2, models.TimestampMixin):
|
||||
"""Stores the mapping between the neutron plugin and the project id"""
|
||||
__tablename__ = 'nsx_project_plugin_mappings'
|
||||
project = sa.Column(sa.String(36), primary_key=True)
|
||||
plugin = sa.Column(sa.Enum('dvs', 'nsx-v', 'nsx-t'), nullable=False)
|
||||
|
133
vmware_nsx/extensions/projectpluginmap.py
Normal file
133
vmware_nsx/extensions/projectpluginmap.py
Normal file
@ -0,0 +1,133 @@
|
||||
# Copyright 2017 VMware. 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 abc
|
||||
|
||||
from neutron.api.v2 import resource_helper
|
||||
from neutron_lib.api import extensions
|
||||
from neutron_lib.db import constants as db_const
|
||||
from neutron_lib import exceptions as nexception
|
||||
|
||||
from vmware_nsx._i18n import _
|
||||
|
||||
PROJECT_PLUGIN_RESOURCE_NAME = "project_plugin_map"
|
||||
# Use dash for alias and collection name
|
||||
EXT_ALIAS = PROJECT_PLUGIN_RESOURCE_NAME.replace('_', '-')
|
||||
PROJECT_PLUGINS = "project_plugin_maps"
|
||||
|
||||
|
||||
class NsxPlugins(object):
|
||||
NSX_V = 'nsx-v'
|
||||
NSX_T = 'nsx-t'
|
||||
DVS = 'dvs'
|
||||
|
||||
|
||||
VALID_TYPES = [NsxPlugins.NSX_V,
|
||||
NsxPlugins.NSX_T,
|
||||
NsxPlugins.DVS]
|
||||
|
||||
RESOURCE_ATTRIBUTE_MAP = {
|
||||
PROJECT_PLUGINS: {
|
||||
'id': {
|
||||
'allow_post': False, 'allow_put': False,
|
||||
'validate': {'type:uuid': None},
|
||||
'is_visible': True},
|
||||
# project is the id of the project mapped by this entry
|
||||
'project': {
|
||||
'allow_post': True, 'allow_put': False, 'is_visible': True},
|
||||
'plugin': {
|
||||
'allow_post': True, 'allow_put': False, 'is_visible': True,
|
||||
'validate': {'type:values': VALID_TYPES}},
|
||||
# tenant id is the id of tenant/project owning this entry
|
||||
'tenant_id': {'allow_post': True, 'allow_put': False,
|
||||
'validate': {
|
||||
'type:string': db_const.PROJECT_ID_FIELD_SIZE},
|
||||
'required_by_policy': True,
|
||||
'is_visible': True},
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class Projectpluginmap(extensions.ExtensionDescriptor):
|
||||
|
||||
@classmethod
|
||||
def get_name(cls):
|
||||
return "Project Plugin Mapping"
|
||||
|
||||
@classmethod
|
||||
def get_alias(cls):
|
||||
return EXT_ALIAS
|
||||
|
||||
@classmethod
|
||||
def get_description(cls):
|
||||
return "Per Project Core Plugin."
|
||||
|
||||
@classmethod
|
||||
def get_updated(cls):
|
||||
return "2017-12-05T00:00:00-00:00"
|
||||
|
||||
@classmethod
|
||||
def get_resources(cls):
|
||||
"""Returns Ext Resources."""
|
||||
plural_mappings = resource_helper.build_plural_mappings(
|
||||
{}, RESOURCE_ATTRIBUTE_MAP)
|
||||
member_actions = {}
|
||||
return resource_helper.build_resource_info(plural_mappings,
|
||||
RESOURCE_ATTRIBUTE_MAP,
|
||||
None,
|
||||
action_map=member_actions,
|
||||
register_quota=True,
|
||||
translate_name=True)
|
||||
|
||||
def get_extended_resources(self, version):
|
||||
if version == "2.0":
|
||||
return RESOURCE_ATTRIBUTE_MAP
|
||||
else:
|
||||
return {}
|
||||
|
||||
|
||||
class ProjectPluginReadOnly(nexception.NotAuthorized):
|
||||
message = _("Project Plugin map entries cannot be modified.")
|
||||
|
||||
|
||||
class ProjectPluginAlreadyExists(nexception.Conflict):
|
||||
message = _("Project Plugin map already exists for project "
|
||||
"%(project_id)s.")
|
||||
|
||||
|
||||
class ProjectPluginMapPluginBase(object):
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_project_plugin_map(self, context, project_plugin_map):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def update_project_plugin_map(self, context, id, project_plugin_map):
|
||||
raise ProjectPluginReadOnly()
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_project_plugin_map(self, context, id, fields=None):
|
||||
pass
|
||||
|
||||
@abc.abstractmethod
|
||||
def delete_project_plugin_map(self, context, id):
|
||||
# TODO(asarfaty): delete when the project is deleted?
|
||||
raise ProjectPluginReadOnly()
|
||||
|
||||
@abc.abstractmethod
|
||||
def get_project_plugin_maps(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
pass
|
131
vmware_nsx/osc/v2/project_plugin_map.py
Normal file
131
vmware_nsx/osc/v2/project_plugin_map.py
Normal file
@ -0,0 +1,131 @@
|
||||
# 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.
|
||||
#
|
||||
|
||||
"""Project Plugin mapping action implementations"""
|
||||
|
||||
from openstack.network import network_service
|
||||
from openstack import resource2 as resource
|
||||
from openstackclient.i18n import _
|
||||
from osc_lib.command import command
|
||||
from osc_lib import utils
|
||||
|
||||
project_plugin_maps_path = "/project-plugin-maps"
|
||||
|
||||
|
||||
class ProjectPluginMap(resource.Resource):
|
||||
resource_key = 'project_plugin_map'
|
||||
resources_key = 'project_plugin_maps'
|
||||
base_path = '/project-plugin-maps'
|
||||
service = network_service.NetworkService()
|
||||
|
||||
# capabilities
|
||||
allow_create = True
|
||||
allow_get = True
|
||||
allow_update = False
|
||||
allow_delete = False
|
||||
allow_list = True
|
||||
|
||||
_query_mapping = resource.QueryParameters(
|
||||
'plugin', 'project', 'tenant_id')
|
||||
|
||||
# Properties
|
||||
id = resource.Body('id')
|
||||
project = resource.Body('project')
|
||||
plugin = resource.Body('plugin')
|
||||
tenant_id = resource.Body('tenant_id')
|
||||
|
||||
|
||||
def _get_columns(item):
|
||||
columns = ['project', 'plugin']
|
||||
return columns, columns
|
||||
|
||||
|
||||
def _get_attrs(parsed_args):
|
||||
attrs = {}
|
||||
if parsed_args.project is not None:
|
||||
attrs['project'] = parsed_args.project
|
||||
|
||||
if parsed_args.plugin is not None:
|
||||
attrs['plugin'] = parsed_args.plugin
|
||||
return attrs
|
||||
|
||||
|
||||
class CreateProjectPluginMap(command.ShowOne):
|
||||
_description = _("Create project plugin map")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(CreateProjectPluginMap, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'project',
|
||||
metavar="<project>",
|
||||
help=_("project")
|
||||
)
|
||||
parser.add_argument(
|
||||
'--plugin',
|
||||
metavar="<plugin>",
|
||||
required=True,
|
||||
help=_('Plugin.)')
|
||||
)
|
||||
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.network
|
||||
attrs = _get_attrs(parsed_args)
|
||||
obj = client._create(ProjectPluginMap, **attrs)
|
||||
display_columns, columns = _get_columns(obj)
|
||||
data = utils.get_item_properties(obj, columns, formatters={})
|
||||
return (display_columns, data)
|
||||
|
||||
|
||||
class ListProjectPluginMap(command.Lister):
|
||||
_description = _("List project plugin mappings")
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.network
|
||||
|
||||
columns = (
|
||||
'project',
|
||||
'plugin'
|
||||
)
|
||||
column_headers = (
|
||||
'Project ID',
|
||||
'Plugin',
|
||||
)
|
||||
|
||||
client = self.app.client_manager.network
|
||||
data = client._list(ProjectPluginMap)
|
||||
return (column_headers,
|
||||
(utils.get_item_properties(
|
||||
s, columns,
|
||||
) for s in data))
|
||||
|
||||
|
||||
class ShowProjectPluginMap(command.ShowOne):
|
||||
_description = _("Display project plugins mapping")
|
||||
|
||||
def get_parser(self, prog_name):
|
||||
parser = super(ShowProjectPluginMap, self).get_parser(prog_name)
|
||||
parser.add_argument(
|
||||
'id',
|
||||
metavar='<id>',
|
||||
help=_('id')
|
||||
)
|
||||
return parser
|
||||
|
||||
def take_action(self, parsed_args):
|
||||
client = self.app.client_manager.network
|
||||
obj = client._get(ProjectPluginMap, parsed_args.id)
|
||||
display_columns, columns = _get_columns(obj)
|
||||
data = utils.get_item_properties(obj, columns)
|
||||
return display_columns, data
|
@ -21,6 +21,7 @@
|
||||
from neutron.db.models import securitygroup # noqa
|
||||
|
||||
from vmware_nsx.plugins.dvs import plugin as dvs
|
||||
from vmware_nsx.plugins.nsx import plugin as nsx
|
||||
from vmware_nsx.plugins.nsx_mh import plugin as nsx_mh
|
||||
from vmware_nsx.plugins.nsx_v import plugin as nsx_v
|
||||
from vmware_nsx.plugins.nsx_v3 import plugin as nsx_v3
|
||||
@ -29,3 +30,4 @@ NsxDvsPlugin = dvs.NsxDvsV2
|
||||
NsxPlugin = nsx_mh.NsxPluginV2
|
||||
NsxVPlugin = nsx_v.NsxVPluginV2
|
||||
NsxV3Plugin = nsx_v3.NsxV3Plugin
|
||||
NsxTVDPlugin = nsx.NsxTVDPlugin
|
||||
|
@ -47,6 +47,10 @@ class NsxPluginBase(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
address_scope_db.AddressScopeDbMixin):
|
||||
"""Common methods for NSX-V and NSX-V3 plugins"""
|
||||
|
||||
@property
|
||||
def plugin_type(self):
|
||||
return "Unknown"
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([net_def.COLLECTION_NAME])
|
||||
def _ext_extend_network_dict(result, netdb):
|
||||
|
@ -61,6 +61,7 @@ from vmware_nsx.db import nsxv_db
|
||||
from vmware_nsx.dhcp_meta import modes as dhcpmeta_modes
|
||||
from vmware_nsx.dvs import dvs
|
||||
from vmware_nsx.dvs import dvs_utils
|
||||
from vmware_nsx.extensions import projectpluginmap
|
||||
from vmware_nsx.plugins.common import plugin as nsx_plugin_common
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
@ -115,6 +116,14 @@ class NsxDvsV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
self._dvs = dvs.SingleDvsManager()
|
||||
self.setup_dhcpmeta_access()
|
||||
|
||||
@staticmethod
|
||||
def plugin_type():
|
||||
return projectpluginmap.NsxPlugins.DVS
|
||||
|
||||
@staticmethod
|
||||
def is_tvd_plugin():
|
||||
return False
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([port_def.COLLECTION_NAME])
|
||||
def _extend_port_dict_binding(result, portdb):
|
||||
|
0
vmware_nsx/plugins/nsx/__init__.py
Normal file
0
vmware_nsx/plugins/nsx/__init__.py
Normal file
574
vmware_nsx/plugins/nsx/plugin.py
Normal file
574
vmware_nsx/plugins/nsx/plugin.py
Normal file
@ -0,0 +1,574 @@
|
||||
# Copyright 2014 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 network as net_def
|
||||
from neutron_lib.api.definitions import port as port_def
|
||||
from neutron_lib.api.definitions import subnet as subnet_def
|
||||
from neutron_lib import context as n_context
|
||||
from neutron_lib.plugins import directory
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron.db import _resource_extend as resource_extend
|
||||
from neutron.db import _utils as db_utils
|
||||
from neutron.db import agents_db
|
||||
from neutron.db import allowedaddresspairs_db as addr_pair_db
|
||||
from neutron.db import api as db_api
|
||||
from neutron.db.availability_zone import router as router_az_db
|
||||
from neutron.db import external_net_db
|
||||
from neutron.db import extradhcpopt_db
|
||||
from neutron.db import extraroute_db
|
||||
from neutron.db import l3_gwmode_db
|
||||
from neutron.db.models import l3 as l3_db_models
|
||||
from neutron.db.models import securitygroup as securitygroup_model # noqa
|
||||
from neutron.db import models_v2
|
||||
from neutron.db import portsecurity_db
|
||||
from neutron.db import quota_db # noqa
|
||||
from neutron.db import securitygroups_db
|
||||
from neutron.quota import resource_registry
|
||||
from neutron_lib.api import validators
|
||||
from neutron_lib import exceptions as n_exc
|
||||
|
||||
from vmware_nsx.common import availability_zones as nsx_com_az
|
||||
from vmware_nsx.common import config # noqa
|
||||
from vmware_nsx.common import exceptions as nsx_exc
|
||||
from vmware_nsx.common import managers as nsx_managers
|
||||
from vmware_nsx.db import (
|
||||
routertype as rt_rtr)
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
from vmware_nsx.db import nsx_portbindings_db as pbin_db
|
||||
from vmware_nsx.extensions import projectpluginmap
|
||||
from vmware_nsx.plugins.common import plugin as nsx_plugin_common
|
||||
from vmware_nsx.plugins.dvs import plugin as dvs
|
||||
from vmware_nsx.plugins.nsx_v import plugin as v
|
||||
from vmware_nsx.plugins.nsx_v3 import plugin as t
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
TVD_PLUGIN_TYPE = "Nsx-TVD"
|
||||
|
||||
|
||||
@resource_extend.has_resource_extenders
|
||||
class NsxTVDPlugin(addr_pair_db.AllowedAddressPairsMixin,
|
||||
agents_db.AgentDbMixin,
|
||||
nsx_plugin_common.NsxPluginBase,
|
||||
rt_rtr.RouterType_mixin,
|
||||
external_net_db.External_net_db_mixin,
|
||||
extraroute_db.ExtraRoute_db_mixin,
|
||||
extradhcpopt_db.ExtraDhcpOptMixin,
|
||||
router_az_db.RouterAvailabilityZoneMixin,
|
||||
l3_gwmode_db.L3_NAT_db_mixin,
|
||||
pbin_db.NsxPortBindingMixin,
|
||||
portsecurity_db.PortSecurityDbMixin,
|
||||
securitygroups_db.SecurityGroupDbMixin,
|
||||
nsx_com_az.NSXAvailabilityZonesPluginCommon,
|
||||
projectpluginmap.ProjectPluginMapPluginBase):
|
||||
|
||||
supported_extension_aliases = ['project-plugin-map']
|
||||
|
||||
__native_bulk_support = False
|
||||
__native_pagination_support = True
|
||||
__native_sorting_support = True
|
||||
|
||||
@resource_registry.tracked_resources(
|
||||
network=models_v2.Network,
|
||||
port=models_v2.Port,
|
||||
subnet=models_v2.Subnet,
|
||||
subnetpool=models_v2.SubnetPool,
|
||||
security_group=securitygroup_model.SecurityGroup,
|
||||
security_group_rule=securitygroup_model.SecurityGroupRule,
|
||||
router=l3_db_models.Router,
|
||||
floatingip=l3_db_models.FloatingIP)
|
||||
def __init__(self):
|
||||
self._extension_manager = nsx_managers.ExtensionManager()
|
||||
LOG.info("Start NSX TVD Plugin")
|
||||
LOG.info("This plugin is experimental!")
|
||||
# Validate configuration
|
||||
config.validate_nsx_config_options()
|
||||
super(NsxTVDPlugin, self).__init__()
|
||||
|
||||
# init the different supported plugins
|
||||
self.init_plugins()
|
||||
|
||||
# init the extensions supported by any of the plugins
|
||||
self.init_extensions()
|
||||
|
||||
@staticmethod
|
||||
def plugin_type():
|
||||
return TVD_PLUGIN_TYPE
|
||||
|
||||
@staticmethod
|
||||
def is_tvd_plugin():
|
||||
return True
|
||||
|
||||
def init_plugins(self):
|
||||
# initialize all supported plugins
|
||||
self.plugins = {}
|
||||
try:
|
||||
self.plugins[projectpluginmap.NsxPlugins.NSX_T] = t.NsxV3Plugin()
|
||||
except Exception as e:
|
||||
LOG.info("NSX-T plugin will not be supported: %s", e)
|
||||
|
||||
try:
|
||||
self.plugins[projectpluginmap.NsxPlugins.NSX_V] = v.NsxVPluginV2()
|
||||
except Exception as e:
|
||||
LOG.info("NSX-V plugin will not be supported: %s", e)
|
||||
|
||||
try:
|
||||
self.plugins[projectpluginmap.NsxPlugins.DVS] = dvs.NsxDvsV2()
|
||||
except Exception as e:
|
||||
LOG.info("DVS plugin will not be supported: %s", e)
|
||||
|
||||
if not len(self.plugins):
|
||||
msg = _("No active plugins were found")
|
||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||
|
||||
# update the default plugin for new projects
|
||||
# TODO(asarfaty): make the default configurable?
|
||||
if projectpluginmap.NsxPlugins.NSX_T in self.plugins:
|
||||
self.default_plugin = projectpluginmap.NsxPlugins.NSX_T
|
||||
else:
|
||||
self.default_plugin = self.plugins[0].key
|
||||
LOG.info("NSX-TVD plugin will use %s as the default plugin",
|
||||
self.default_plugin)
|
||||
|
||||
def get_plugin_by_type(self, plugin_type):
|
||||
return self.plugins.get(plugin_type)
|
||||
|
||||
def init_extensions(self):
|
||||
# Support all the extensions supported by any of the plugins
|
||||
extensions = []
|
||||
for plugin in self.plugins:
|
||||
extensions.extend(self.plugins[plugin].supported_extension_aliases)
|
||||
self.supported_extension_aliases = list(set(extensions))
|
||||
|
||||
# mark extensions which are supported by only one of the plugins
|
||||
self._unsupported_fields = {}
|
||||
for plugin in self.plugins:
|
||||
# TODO(asarfaty): add other resources here
|
||||
plugin_type = self.plugins[plugin].plugin_type()
|
||||
self._unsupported_fields[plugin_type] = {'router': []}
|
||||
|
||||
# router size and type are supported only by the V plugin
|
||||
self._unsupported_fields[t.NsxV3Plugin.plugin_type()]['router'] = [
|
||||
'router_size', 'router_type']
|
||||
|
||||
def _validate_obj_extensions(self, data, plugin_type, obj_type):
|
||||
"""prevent configuration of unsupported extensions"""
|
||||
for field in self._unsupported_fields[plugin_type][obj_type]:
|
||||
if validators.is_attr_set(data.get(field)):
|
||||
err_msg = (_('Can not support %(field)s extension for '
|
||||
'%(obj_type)s %(p)s plugin') % {
|
||||
'field': field,
|
||||
'obj_type': obj_type,
|
||||
'p': plugin_type})
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def _cleanup_obj_fields(self, data, plugin_type, obj_type):
|
||||
"""Remove data of unsupported extensions"""
|
||||
for field in self._unsupported_fields[plugin_type][obj_type]:
|
||||
if field in data:
|
||||
del data[field]
|
||||
|
||||
def _list_availability_zones(self, context, filters=None):
|
||||
p = self._get_plugin_from_project(context, context.project_id)
|
||||
return p._list_availability_zones(context, filters=filters)
|
||||
|
||||
def validate_availability_zones(self, context, resource_type,
|
||||
availability_zones):
|
||||
p = self._get_plugin_from_project(context, context.project_id)
|
||||
return p.validate_availability_zones(context, resource_type,
|
||||
availability_zones)
|
||||
|
||||
def _get_plugin_from_net_id(self, context, net_id):
|
||||
# get the network using the super plugin - here we use the
|
||||
# _get_network (so as not to call the make dict method)
|
||||
network = super(NsxTVDPlugin, self)._get_network(context, net_id)
|
||||
return self._get_plugin_from_project(context, network['tenant_id'])
|
||||
|
||||
def get_network_availability_zones(self, net_db):
|
||||
ctx = n_context.get_admin_context()
|
||||
p = self._get_plugin_from_project(ctx, net_db['tenant_id'])
|
||||
return p.get_network_availability_zones(net_db)
|
||||
|
||||
def create_network(self, context, network):
|
||||
net_data = network['network']
|
||||
tenant_id = net_data['tenant_id']
|
||||
self._ensure_default_security_group(context, tenant_id)
|
||||
p = self._get_plugin_from_project(context, tenant_id)
|
||||
return p.create_network(context, network)
|
||||
|
||||
def delete_network(self, context, id):
|
||||
p = self._get_plugin_from_net_id(context, id)
|
||||
p.delete_network(context, id)
|
||||
|
||||
def get_network(self, context, id, fields=None):
|
||||
p = self._get_plugin_from_net_id(context, id)
|
||||
return p.get_network(context, id, fields=fields)
|
||||
|
||||
def get_networks(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
filters = filters or {}
|
||||
with db_api.context_manager.reader.using(context):
|
||||
networks = (
|
||||
super(NsxTVDPlugin, self).get_networks(
|
||||
context, filters, fields, sorts,
|
||||
limit, marker, page_reverse))
|
||||
for net in networks:
|
||||
p = self._get_plugin_from_project(context, net['tenant_id'])
|
||||
p._extend_get_network_dict_provider(context, net)
|
||||
return (networks if not fields else
|
||||
[db_utils.resource_fields(network,
|
||||
fields) for network in networks])
|
||||
|
||||
def update_network(self, context, id, network):
|
||||
p = self._get_plugin_from_net_id(context, id)
|
||||
return p.update_network(context, id, network)
|
||||
|
||||
def create_port(self, context, port):
|
||||
id = port['port']['network_id']
|
||||
p = self._get_plugin_from_net_id(context, id)
|
||||
return p.create_port(context, port)
|
||||
|
||||
def update_port(self, context, id, port):
|
||||
db_port = self._get_port(context, id)
|
||||
p = self._get_plugin_from_net_id(context, db_port['network_id'])
|
||||
return p.update_port(context, id, port)
|
||||
|
||||
def delete_port(self, context, id, **kwargs):
|
||||
db_port = self._get_port(context, id)
|
||||
p = self._get_plugin_from_net_id(context, db_port['network_id'])
|
||||
p.delete_port(context, id, **kwargs)
|
||||
|
||||
def get_port(self, context, id, fields=None):
|
||||
db_port = self._get_port(context, id)
|
||||
p = self._get_plugin_from_net_id(context, db_port['network_id'])
|
||||
return p.get_port(context, id, fields=fields)
|
||||
|
||||
def get_ports(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
filters = filters or {}
|
||||
with db_api.context_manager.reader.using(context):
|
||||
ports = (
|
||||
super(NsxTVDPlugin, self).get_ports(
|
||||
context, filters, fields, sorts,
|
||||
limit, marker, page_reverse))
|
||||
# Add port extensions
|
||||
for port in ports:
|
||||
if 'id' in port:
|
||||
port_model = self._get_port(context, port['id'])
|
||||
resource_extend.apply_funcs('ports', port, port_model)
|
||||
p = self._get_plugin_from_net_id(context, port['network_id'])
|
||||
p._extend_get_port_dict_qos_and_binding(context, port)
|
||||
p._remove_provider_security_groups_from_list(port)
|
||||
return (ports if not fields else
|
||||
[db_utils.resource_fields(port, fields) for port in ports])
|
||||
|
||||
def get_subnet(self, context, id, fields=None):
|
||||
db_subnet = self._get_subnet(context, id)
|
||||
p = self._get_plugin_from_net_id(context, db_subnet['network_id'])
|
||||
return p.get_subnet(context, id, fields=fields)
|
||||
|
||||
def get_subnets(self, context, filters=None, fields=None, sorts=None,
|
||||
limit=None, marker=None, page_reverse=False):
|
||||
# The subnets is tricky as the metadata requests make use of the
|
||||
# get subnet. So there are two use cases here:
|
||||
# 1. that the metadata request returns a value
|
||||
# 2. that this is a general subnet query.
|
||||
# If none found then we return default plugin subnets
|
||||
default_plugin_subnets = []
|
||||
for plugin in self.plugins.values():
|
||||
subnets = plugin.get_subnets(context, filters=filters,
|
||||
fields=fields, sorts=sorts,
|
||||
limit=limit, marker=marker,
|
||||
page_reverse=page_reverse)
|
||||
if subnets:
|
||||
return subnets
|
||||
if self.plugins[self.default_plugin] == plugin:
|
||||
default_plugin_subnets = subnets
|
||||
return default_plugin_subnets
|
||||
|
||||
def delete_subnet(self, context, id):
|
||||
db_subnet = self._get_subnet(context, id)
|
||||
p = self._get_plugin_from_net_id(context, db_subnet['network_id'])
|
||||
p.delete_subnet(context, id)
|
||||
|
||||
def create_subnet(self, context, subnet):
|
||||
id = subnet['subnet']['network_id']
|
||||
p = self._get_plugin_from_net_id(context, id)
|
||||
return p.create_subnet(context, subnet)
|
||||
|
||||
def update_subnet(self, context, id, subnet):
|
||||
db_subnet = self._get_subnet(context, id)
|
||||
p = self._get_plugin_from_net_id(context, db_subnet['network_id'])
|
||||
return p.update_subnet(context, id, subnet)
|
||||
|
||||
def get_router_availability_zones(self, router):
|
||||
ctx = n_context.get_admin_context()
|
||||
p = self._get_plugin_from_project(ctx, router['tenant_id'])
|
||||
return p.get_router_availability_zones(router)
|
||||
|
||||
def _validate_router_gw_plugin(self, context, router_plugin,
|
||||
gw_info):
|
||||
if gw_info and gw_info.get('network_id'):
|
||||
net_plugin = self._get_plugin_from_net_id(
|
||||
context, gw_info['network_id'])
|
||||
if net_plugin.plugin_type() != router_plugin.plugin_type():
|
||||
err_msg = (_('Router gateway should belong to the %s plugin '
|
||||
'as the router') % router_plugin.plugin_type())
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def _validate_router_interface_plugin(self, context, router_plugin,
|
||||
interface_info):
|
||||
is_port, is_sub = self._validate_interface_info(interface_info)
|
||||
if is_port:
|
||||
net_id = self.get_port(
|
||||
context, interface_info['port_id'])['network_id']
|
||||
elif is_sub:
|
||||
net_id = self.get_subnet(
|
||||
context, interface_info['subnet_id'])['network_id']
|
||||
net_plugin = self._get_plugin_from_net_id(context, net_id)
|
||||
if net_plugin.plugin_type() != router_plugin.plugin_type():
|
||||
err_msg = (_('Router interface should belong to the %s plugin '
|
||||
'as the router') % router_plugin.plugin_type())
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def _get_plugin_from_router_id(self, context, router_id):
|
||||
# get the router using the super plugin - here we use the
|
||||
# _get_router (so as not to call the make dict method)
|
||||
router = super(NsxTVDPlugin, self)._get_router(context, router_id)
|
||||
return self._get_plugin_from_project(context, router['tenant_id'])
|
||||
|
||||
def create_router(self, context, router):
|
||||
tenant_id = router['router']['tenant_id']
|
||||
self._ensure_default_security_group(context, tenant_id)
|
||||
p = self._get_plugin_from_project(context, tenant_id)
|
||||
self._validate_router_gw_plugin(context, p, router['router'].get(
|
||||
'external_gateway_info'))
|
||||
self._validate_obj_extensions(
|
||||
router['router'], p.plugin_type(), 'router')
|
||||
new_router = p.create_router(context, router)
|
||||
self._cleanup_obj_fields(
|
||||
router['router'], p.plugin_type(), 'router')
|
||||
return new_router
|
||||
|
||||
def update_router(self, context, router_id, router):
|
||||
p = self._get_plugin_from_router_id(context, router_id)
|
||||
self._validate_router_gw_plugin(context, p, router['router'].get(
|
||||
'external_gateway_info'))
|
||||
self._validate_obj_extensions(
|
||||
router['router'], p.plugin_type(), 'router')
|
||||
return p.update_router(context, router_id, router)
|
||||
|
||||
def get_router(self, context, id, fields=None):
|
||||
p = self._get_plugin_from_router_id(context, id)
|
||||
router = p.get_router(context, id, fields=fields)
|
||||
self._cleanup_obj_fields(router, p.plugin_type(), 'router')
|
||||
return router
|
||||
|
||||
def add_router_interface(self, context, router_id, interface_info):
|
||||
p = self._get_plugin_from_router_id(context, router_id)
|
||||
self._validate_router_interface_plugin(context, p, interface_info)
|
||||
return p.add_router_interface(context, router_id, interface_info)
|
||||
|
||||
def remove_router_interface(self, context, router_id, interface_info):
|
||||
p = self._get_plugin_from_router_id(context, router_id)
|
||||
return p.remove_router_interface(context, router_id, interface_info)
|
||||
|
||||
def _validate_fip_router_plugin(self, context, fip_plugin, fip_data):
|
||||
if 'router_id' in fip_data:
|
||||
router_plugin = self._get_plugin_from_router_id(
|
||||
context, fip_data['router_id'])
|
||||
if router_plugin.plugin_type() != fip_plugin.plugin_type():
|
||||
err_msg = (_('Floatingip router should belong to the %s '
|
||||
'plugin as the floatingip') %
|
||||
fip_plugin.plugin_type())
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def create_floatingip(self, context, floatingip):
|
||||
net_id = floatingip['floatingip']['floating_network_id']
|
||||
p = self._get_plugin_from_net_id(context, net_id)
|
||||
self._validate_fip_router_plugin(context, p, floatingip['floatingip'])
|
||||
return p.create_floatingip(context, floatingip)
|
||||
|
||||
def update_floatingip(self, context, id, floatingip):
|
||||
fip = self._get_floatingip(context, id)
|
||||
net_id = fip['floating_network_id']
|
||||
p = self._get_plugin_from_net_id(context, net_id)
|
||||
self._validate_fip_router_plugin(context, p, floatingip['floatingip'])
|
||||
return p.update_floatingip(context, id, floatingip)
|
||||
|
||||
def delete_floatingip(self, context, id):
|
||||
fip = self._get_floatingip(context, id)
|
||||
net_id = fip['floating_network_id']
|
||||
p = self._get_plugin_from_net_id(context, net_id)
|
||||
return p.delete_floatingip(context, id)
|
||||
|
||||
def disassociate_floatingips(self, context, port_id):
|
||||
db_port = self._get_port(context, port_id)
|
||||
p = self._get_plugin_from_net_id(context, db_port['network_id'])
|
||||
return p.disassociate_floatingips(context, port_id)
|
||||
|
||||
def _get_plugin_from_sg_id(self, context, sg_id):
|
||||
# get the router using the super plugin - here we use the
|
||||
# _get_router (so as not to call the make dict method)
|
||||
sg = super(NsxTVDPlugin, self)._get_security_group(context, sg_id)
|
||||
return self._get_plugin_from_project(context, sg['tenant_id'])
|
||||
|
||||
# TODO(asarfaty): no need to create on both any more?
|
||||
def create_security_group(self, context, security_group,
|
||||
default_sg=False):
|
||||
if not default_sg:
|
||||
secgroup = security_group['security_group']
|
||||
tenant_id = secgroup['tenant_id']
|
||||
self._ensure_default_security_group(context, tenant_id)
|
||||
|
||||
p = self._get_plugin_from_project(context, context.project_id)
|
||||
return p.create_security_group(context, security_group,
|
||||
default_sg=default_sg)
|
||||
|
||||
def delete_security_group(self, context, id):
|
||||
p = self._get_plugin_from_sg_id(context, id)
|
||||
p.delete_security_group(context, id)
|
||||
# self._v.delete_security_group(context, id, delete_base=False)
|
||||
# self._t.delete_security_group(context, id)
|
||||
|
||||
def update_security_group(self, context, id, security_group):
|
||||
p = self._get_plugin_from_sg_id(context, id)
|
||||
return p.update_security_group(context, id, security_group)
|
||||
#self._t.update_security_group(context, id, security_group)
|
||||
#return self._v.update_security_group(context, id, security_group)
|
||||
|
||||
def create_security_group_rule_bulk(self, context, security_group_rules):
|
||||
p = self._get_plugin_from_project(context, context.project_id)
|
||||
return p.create_security_group_rule_bulk(context,
|
||||
security_group_rules)
|
||||
# sg_rules = security_group_rules['security_group_rules']
|
||||
# for r in sg_rules:
|
||||
# r['security_group_rule']['id'] = (
|
||||
# r['security_group_rule'].get('id') or
|
||||
# uuidutils.generate_uuid())
|
||||
# sgs = self._t.create_security_group_rule_bulk(context,
|
||||
# security_group_rules)
|
||||
# self._v.create_security_group_rule_bulk(context,
|
||||
# security_group_rules,
|
||||
# base_create=False)
|
||||
# return sgs
|
||||
|
||||
def create_security_group_rule(self, context, security_group_rule):
|
||||
p = self._get_plugin_from_project(context, context.project_id)
|
||||
return p.create_security_group_rule(context, security_group_rule)
|
||||
# security_group_rule['security_group_rule']['id'] = (
|
||||
# security_group_rule['security_group_rule'].get('id') or
|
||||
# uuidutils.generate_uuid())
|
||||
# sg = self._t.create_security_group_rule(context, security_group_rule)
|
||||
# self._v.create_security_group_rule(context, security_group_rule,
|
||||
# create_base=False)
|
||||
# return sg
|
||||
|
||||
def delete_security_group_rule(self, context, id):
|
||||
p = self._get_plugin_from_sg_id(context, id)
|
||||
p.delete_security_group_rule(context, id)
|
||||
# self._v.delete_security_group_rule(context, id, delete_base=False)
|
||||
# self._t.delete_security_group_rule(context, id)
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([net_def.COLLECTION_NAME])
|
||||
def _ext_extend_network_dict(result, netdb):
|
||||
ctx = n_context.get_admin_context()
|
||||
# get the core plugin as this is a static method with no 'self'
|
||||
plugin = directory.get_plugin()
|
||||
p = plugin._get_plugin_from_project(ctx, netdb['tenant_id'])
|
||||
with db_api.context_manager.writer.using(ctx):
|
||||
p._extension_manager.extend_network_dict(
|
||||
ctx.session, netdb, result)
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([port_def.COLLECTION_NAME])
|
||||
def _ext_extend_port_dict(result, portdb):
|
||||
ctx = n_context.get_admin_context()
|
||||
# get the core plugin as this is a static method with no 'self'
|
||||
plugin = directory.get_plugin()
|
||||
p = plugin._get_plugin_from_project(ctx, portdb['tenant_id'])
|
||||
with db_api.context_manager.writer.using(ctx):
|
||||
p._extension_manager.extend_port_dict(
|
||||
ctx.session, portdb, result)
|
||||
|
||||
@staticmethod
|
||||
@resource_extend.extends([subnet_def.COLLECTION_NAME])
|
||||
def _ext_extend_subnet_dict(result, subnetdb):
|
||||
ctx = n_context.get_admin_context()
|
||||
# get the core plugin as this is a static method with no 'self'
|
||||
plugin = directory.get_plugin()
|
||||
p = plugin._get_plugin_from_project(ctx, subnetdb['tenant_id'])
|
||||
with db_api.context_manager.writer.using(ctx):
|
||||
p._extension_manager.extend_subnet_dict(
|
||||
ctx.session, subnetdb, result)
|
||||
|
||||
def _get_project_plugin_dict(self, data):
|
||||
return {'id': data['project'],
|
||||
'project': data['project'],
|
||||
'plugin': data['plugin'],
|
||||
'tenant_id': data['project']}
|
||||
|
||||
def create_project_plugin_map(self, context, project_plugin_map):
|
||||
# TODO(asarfaty): Validate project id exists
|
||||
data = project_plugin_map['project_plugin_map']
|
||||
if nsx_db.get_project_plugin_mapping(
|
||||
context.session, data['project']):
|
||||
raise projectpluginmap.ProjectPluginAlreadyExists(
|
||||
project_id=data['project'])
|
||||
nsx_db.add_project_plugin_mapping(context.session,
|
||||
data['project'],
|
||||
data['plugin'])
|
||||
return self._get_project_plugin_dict(data)
|
||||
|
||||
def get_project_plugin_map(self, context, id, fields=None):
|
||||
data = nsx_db.get_project_plugin_mapping(context.session, id)
|
||||
if data:
|
||||
return self._get_project_plugin_dict(data)
|
||||
else:
|
||||
raise n_exc.ObjectNotFound(id=id)
|
||||
|
||||
def get_project_plugin_maps(self, context, filters=None, fields=None,
|
||||
sorts=None, limit=None, marker=None,
|
||||
page_reverse=False):
|
||||
# TODO(asarfaty) filter the results
|
||||
mappings = nsx_db.get_project_plugin_mappings(context.session)
|
||||
return [self._get_project_plugin_dict(data) for data in mappings]
|
||||
|
||||
def _get_plugin_from_project(self, context, project_id):
|
||||
"""Get the correct plugin for this project.
|
||||
|
||||
Look for the project in the DB.
|
||||
If not there - add an entry with the default plugin
|
||||
"""
|
||||
plugin_type = self.default_plugin
|
||||
mapping = nsx_db.get_project_plugin_mapping(
|
||||
context.session, project_id)
|
||||
if mapping:
|
||||
plugin_type = mapping['plugin']
|
||||
else:
|
||||
self.create_project_plugin_map(context,
|
||||
{'project_plugin_map': {'plugin': plugin_type,
|
||||
'project': project_id}})
|
||||
if not self.plugins.get(plugin_type):
|
||||
msg = (_("Cannot use unsupported plugin %(plugin)s for project "
|
||||
"%(project)s") % {'plugin': plugin_type,
|
||||
'project': project_id})
|
||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||
|
||||
LOG.debug("Using %s plugin", plugin_type)
|
||||
return self.plugins[plugin_type]
|
24
vmware_nsx/plugins/nsx/utils.py
Normal file
24
vmware_nsx/plugins/nsx/utils.py
Normal file
@ -0,0 +1,24 @@
|
||||
# Copyright 2014 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 oslo_config import cfg
|
||||
|
||||
|
||||
def is_tvd_core_plugin():
|
||||
core_plugin = cfg.CONF.core_plugin
|
||||
if (core_plugin.endswith('NsxTVDPlugin') or
|
||||
core_plugin.endswith('vmware_nsxtvd')):
|
||||
return True
|
||||
return False
|
@ -204,10 +204,11 @@ class NsxVAvailabilityZone(common_az.ConfiguredAvailabilityZone):
|
||||
|
||||
class NsxVAvailabilityZones(common_az.ConfiguredAvailabilityZones):
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, validate_default=False):
|
||||
super(NsxVAvailabilityZones, self).__init__(
|
||||
cfg.CONF.nsxv.availability_zones,
|
||||
NsxVAvailabilityZone)
|
||||
NsxVAvailabilityZone,
|
||||
validate_default=validate_default)
|
||||
|
||||
def get_inventory(self):
|
||||
"""Return a set of relevant resources in all the availability zones
|
||||
|
@ -120,12 +120,14 @@ from vmware_nsx.extensions import dhcp_mtu as ext_dhcp_mtu
|
||||
from vmware_nsx.extensions import dns_search_domain as ext_dns_search_domain
|
||||
from vmware_nsx.extensions import maclearning as mac_ext
|
||||
from vmware_nsx.extensions import nsxpolicy
|
||||
from vmware_nsx.extensions import projectpluginmap
|
||||
from vmware_nsx.extensions import providersecuritygroup as provider_sg
|
||||
from vmware_nsx.extensions import routersize
|
||||
from vmware_nsx.extensions import secgroup_rule_local_ip_prefix
|
||||
from vmware_nsx.extensions import securitygrouplogging as sg_logging
|
||||
from vmware_nsx.extensions import securitygrouppolicy as sg_policy
|
||||
from vmware_nsx.plugins.common import plugin as nsx_plugin_common
|
||||
from vmware_nsx.plugins.nsx import utils as tvd_utils
|
||||
from vmware_nsx.plugins.nsx_v import availability_zones as nsx_az
|
||||
from vmware_nsx.plugins.nsx_v import managers
|
||||
from vmware_nsx.plugins.nsx_v import md_proxy as nsx_v_md_proxy
|
||||
@ -217,8 +219,14 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
router=l3_db_models.Router,
|
||||
floatingip=l3_db_models.FloatingIP)
|
||||
def __init__(self):
|
||||
self._extension_manager = nsx_managers.ExtensionManager()
|
||||
self._is_sub_plugin = tvd_utils.is_tvd_core_plugin()
|
||||
super(NsxVPluginV2, self).__init__()
|
||||
if self._is_sub_plugin:
|
||||
extension_drivers = cfg.CONF.nsx_tvd.nsx_v_extension_drivers
|
||||
else:
|
||||
extension_drivers = cfg.CONF.nsx_extension_drivers
|
||||
self._extension_manager = nsx_managers.ExtensionManager(
|
||||
extension_drivers=extension_drivers)
|
||||
# Bind the dummy L3 notifications
|
||||
self.l3_rpc_notifier = l3_rpc_agent_api.L3NotifyAPI()
|
||||
self.init_is_complete = False
|
||||
@ -311,6 +319,14 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Bind QoS notifications
|
||||
qos_driver.register(self)
|
||||
|
||||
@staticmethod
|
||||
def plugin_type():
|
||||
return projectpluginmap.NsxPlugins.NSX_V
|
||||
|
||||
@staticmethod
|
||||
def is_tvd_plugin():
|
||||
return False
|
||||
|
||||
def init_complete(self, resource, event, trigger, payload=None):
|
||||
with locking.LockManager.get_lock('plugin-init-complete'):
|
||||
if self.init_is_complete:
|
||||
@ -935,7 +951,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
if vnic_id is None or added_sgids is None:
|
||||
return
|
||||
for add_sg in added_sgids:
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(session, add_sg)
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(session, add_sg,
|
||||
moref=True)
|
||||
if nsx_sg_id is None:
|
||||
LOG.warning("NSX security group not found for %s", add_sg)
|
||||
else:
|
||||
@ -958,7 +975,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
return
|
||||
# Remove vnic from delete security groups binding
|
||||
for del_sg in deleted_sgids:
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(session, del_sg)
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(session, del_sg,
|
||||
moref=True)
|
||||
if nsx_sg_id is None:
|
||||
LOG.warning("NSX security group not found for %s", del_sg)
|
||||
else:
|
||||
@ -994,7 +1012,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
return '%s.%03d' % (device_id, port_index)
|
||||
|
||||
def init_availability_zones(self):
|
||||
self._availability_zones_data = nsx_az.NsxVAvailabilityZones()
|
||||
validate_default = not self._is_sub_plugin
|
||||
self._availability_zones_data = nsx_az.NsxVAvailabilityZones(
|
||||
validate_default=validate_default)
|
||||
|
||||
def _list_availability_zones(self, context, filters=None):
|
||||
#TODO(asarfaty): We may need to use the filters arg, but now it
|
||||
@ -1010,13 +1030,19 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
obj_data):
|
||||
if az_def.AZ_HINTS in obj_data:
|
||||
self.validate_availability_zones(context, resource_type,
|
||||
obj_data[az_def.AZ_HINTS])
|
||||
obj_data[az_def.AZ_HINTS],
|
||||
force=True)
|
||||
|
||||
def validate_availability_zones(self, context, resource_type,
|
||||
availability_zones):
|
||||
availability_zones, force=False):
|
||||
"""Verify that the availability zones exist, and only 1 hint
|
||||
was set.
|
||||
"""
|
||||
# This method is called directly from this plugin but also from
|
||||
# registered callbacks
|
||||
if self._is_sub_plugin and not force:
|
||||
# validation should be done together for both plugins
|
||||
return
|
||||
return self.validate_obj_azs(availability_zones)
|
||||
|
||||
def _prepare_spoofguard_policy(self, network_type, net_data, net_morefs):
|
||||
@ -4137,7 +4163,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
def update_security_group(self, context, id, security_group):
|
||||
s = security_group['security_group']
|
||||
self._validate_security_group(context, s, False, id=id)
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(context.session, id)
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(context.session, id,
|
||||
moref=True)
|
||||
section_uri = self._get_section_uri(context.session, id)
|
||||
section_needs_update = False
|
||||
|
||||
@ -4190,7 +4217,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
|
||||
return sg_data
|
||||
|
||||
def delete_security_group(self, context, id):
|
||||
def delete_security_group(self, context, id, delete_base=True):
|
||||
"""Delete a security group."""
|
||||
self._prevent_non_admin_delete_provider_sg(context, id)
|
||||
self._prevent_non_admin_delete_policy_sg(context, id)
|
||||
@ -4200,10 +4227,12 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
section_uri = self._get_section_uri(context.session, id)
|
||||
|
||||
# Find nsx security group
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(context.session, id)
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(context.session, id,
|
||||
moref=True)
|
||||
|
||||
# Delete neutron security group
|
||||
super(NsxVPluginV2, self).delete_security_group(context, id)
|
||||
if delete_base:
|
||||
# Delete neutron security group
|
||||
super(NsxVPluginV2, self).delete_security_group(context, id)
|
||||
|
||||
# Delete nsx rule sections
|
||||
self._delete_section(section_uri)
|
||||
@ -4228,7 +4257,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
if nsx_sg_id is None:
|
||||
# Find nsx security group for neutron security group
|
||||
nsx_sg_id = nsx_db.get_nsx_security_group_id(
|
||||
context.session, rule['security_group_id'])
|
||||
context.session, rule['security_group_id'],
|
||||
moref=True)
|
||||
|
||||
# Find the remote nsx security group id, which might be the current
|
||||
# one. In case of the default security-group, the associated
|
||||
@ -4237,7 +4267,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
remote_nsx_sg_id = nsx_sg_id
|
||||
else:
|
||||
remote_nsx_sg_id = nsx_db.get_nsx_security_group_id(
|
||||
context.session, rule['remote_group_id'])
|
||||
context.session, rule['remote_group_id'], moref=True)
|
||||
|
||||
# Get source and destination containers from rule
|
||||
if rule['direction'] == 'ingress':
|
||||
@ -4283,12 +4313,15 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
tag='Project_%s' % rule['tenant_id'])
|
||||
return nsx_rule
|
||||
|
||||
def create_security_group_rule(self, context, security_group_rule):
|
||||
def create_security_group_rule(self, context, security_group_rule,
|
||||
create_base=True):
|
||||
"""Create a single security group rule."""
|
||||
bulk_rule = {'security_group_rules': [security_group_rule]}
|
||||
return self.create_security_group_rule_bulk(context, bulk_rule)[0]
|
||||
return self.create_security_group_rule_bulk(
|
||||
context, bulk_rule, create_base=create_base)[0]
|
||||
|
||||
def create_security_group_rule_bulk(self, context, security_group_rules):
|
||||
def create_security_group_rule_bulk(self, context, security_group_rules,
|
||||
create_base=True):
|
||||
"""Create security group rules.
|
||||
|
||||
:param security_group_rules: list of rules to create
|
||||
@ -4321,7 +4354,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
rule = r['security_group_rule']
|
||||
if not self._check_local_ip_prefix(context, rule):
|
||||
rule[secgroup_rule_local_ip_prefix.LOCAL_IP_PREFIX] = None
|
||||
rule['id'] = uuidutils.generate_uuid()
|
||||
rule['id'] = rule.get('id') or uuidutils.generate_uuid()
|
||||
ruleids.add(rule['id'])
|
||||
nsx_rules.append(
|
||||
self._create_nsx_rule(context, rule,
|
||||
@ -4340,18 +4373,23 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Save new rules in Database, including mappings between Nsx rules
|
||||
# and Neutron security-groups rules
|
||||
with db_api.context_manager.writer.using(context):
|
||||
new_rule_list = super(
|
||||
NsxVPluginV2, self).create_security_group_rule_bulk_native(
|
||||
context, security_group_rules)
|
||||
if create_base:
|
||||
new_rule_list = super(
|
||||
NsxVPluginV2,
|
||||
self).create_security_group_rule_bulk_native(
|
||||
context, security_group_rules)
|
||||
for i, r in enumerate(sg_rules):
|
||||
self._process_security_group_rule_properties(
|
||||
context, new_rule_list[i],
|
||||
r['security_group_rule'])
|
||||
else:
|
||||
new_rule_list = sg_rules
|
||||
for pair in rule_pairs:
|
||||
neutron_rule_id = pair['neutron_id']
|
||||
nsx_rule_id = pair['nsx_id']
|
||||
if neutron_rule_id in ruleids:
|
||||
nsxv_db.add_neutron_nsx_rule_mapping(
|
||||
context.session, neutron_rule_id, nsx_rule_id)
|
||||
for i, r in enumerate(sg_rules):
|
||||
self._process_security_group_rule_properties(
|
||||
context, new_rule_list[i], r['security_group_rule'])
|
||||
except Exception:
|
||||
with excutils.save_and_reraise_exception():
|
||||
for nsx_rule_id in [p['nsx_id'] for p in rule_pairs
|
||||
@ -4363,7 +4401,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
LOG.exception("Failed to create security group rule")
|
||||
return new_rule_list
|
||||
|
||||
def delete_security_group_rule(self, context, id):
|
||||
def delete_security_group_rule(self, context, id, delete_base=True):
|
||||
"""Delete a security group rule."""
|
||||
rule_db = self._get_security_group_rule(context, id)
|
||||
security_group_id = rule_db['security_group_id']
|
||||
@ -4383,8 +4421,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
LOG.debug("Security group rule %(id)s deleted, backend "
|
||||
"nsx-rule %(nsx_rule_id)s doesn't exist.",
|
||||
{'id': id, 'nsx_rule_id': nsx_rule_id})
|
||||
|
||||
securitygroup.SecurityGroupRule.delete_objects(context, id=id)
|
||||
if delete_base:
|
||||
securitygroup.SecurityGroupRule.delete_objects(context, id=id)
|
||||
|
||||
def _remove_vnic_from_spoofguard_policy(self, session, net_id, vnic_id):
|
||||
policy_id = nsxv_db.get_spoofguard_policy_id(session, net_id)
|
||||
|
@ -204,10 +204,11 @@ class NsxV3AvailabilityZones(common_az.ConfiguredAvailabilityZones):
|
||||
|
||||
default_name = DEFAULT_NAME
|
||||
|
||||
def __init__(self):
|
||||
def __init__(self, validate_default=False):
|
||||
super(NsxV3AvailabilityZones, self).__init__(
|
||||
cfg.CONF.nsx_v3.availability_zones,
|
||||
NsxV3AvailabilityZone)
|
||||
NsxV3AvailabilityZone,
|
||||
validate_default=validate_default)
|
||||
|
||||
def dhcp_relay_configured(self):
|
||||
for az in self.availability_zones.values():
|
||||
|
@ -99,9 +99,11 @@ from vmware_nsx.db import maclearning as mac_db
|
||||
from vmware_nsx.dhcp_meta import rpc as nsx_rpc
|
||||
from vmware_nsx.extensions import advancedserviceproviders as as_providers
|
||||
from vmware_nsx.extensions import maclearning as mac_ext
|
||||
from vmware_nsx.extensions import projectpluginmap
|
||||
from vmware_nsx.extensions import providersecuritygroup as provider_sg
|
||||
from vmware_nsx.extensions import securitygrouplogging as sg_logging
|
||||
from vmware_nsx.plugins.common import plugin as nsx_plugin_common
|
||||
from vmware_nsx.plugins.nsx import utils as tvd_utils
|
||||
from vmware_nsx.plugins.nsx_v3 import availability_zones as nsx_az
|
||||
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
|
||||
from vmware_nsx.services.fwaas.common import utils as fwaas_utils
|
||||
@ -210,9 +212,15 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
router=l3_db_models.Router,
|
||||
floatingip=l3_db_models.FloatingIP)
|
||||
def __init__(self):
|
||||
self._is_sub_plugin = tvd_utils.is_tvd_core_plugin()
|
||||
nsxlib_utils.set_is_attr_callback(validators.is_attr_set)
|
||||
self._extend_fault_map()
|
||||
self._extension_manager = managers.ExtensionManager()
|
||||
if self._is_sub_plugin:
|
||||
extension_drivers = cfg.CONF.nsx_tvd.nsx_v3_extension_drivers
|
||||
else:
|
||||
extension_drivers = cfg.CONF.nsx_extension_drivers
|
||||
self._extension_manager = managers.ExtensionManager(
|
||||
extension_drivers=extension_drivers)
|
||||
super(NsxV3Plugin, self).__init__()
|
||||
# Bind the dummy L3 notifications
|
||||
self.l3_rpc_notifier = l3_rpc_agent_api.L3NotifyAPI()
|
||||
@ -298,6 +306,14 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
# Register NSXv3 trunk driver to support trunk extensions
|
||||
self.trunk_driver = trunk_driver.NsxV3TrunkDriver.create(self)
|
||||
|
||||
@staticmethod
|
||||
def plugin_type():
|
||||
return projectpluginmap.NsxPlugins.NSX_T
|
||||
|
||||
@staticmethod
|
||||
def is_tvd_plugin():
|
||||
return False
|
||||
|
||||
def init_complete(self, resource, event, trigger, payload=None):
|
||||
with locking.LockManager.get_lock('plugin-init-complete'):
|
||||
if self.init_is_complete:
|
||||
@ -364,7 +380,9 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
"DHCP metadata")
|
||||
LOG.error(msg)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
self._availability_zones_data = nsx_az.NsxV3AvailabilityZones()
|
||||
validate_default = not self._is_sub_plugin
|
||||
self._availability_zones_data = nsx_az.NsxV3AvailabilityZones(
|
||||
validate_default=validate_default)
|
||||
|
||||
def _init_nsx_profiles(self):
|
||||
LOG.debug("Initializing NSX v3 port spoofguard switching profile")
|
||||
@ -1027,8 +1045,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
# validate the availability zone, and get the AZ object
|
||||
if az_def.AZ_HINTS in net_data:
|
||||
self.validate_availability_zones(context, 'network',
|
||||
net_data[az_def.AZ_HINTS])
|
||||
self._validate_availability_zones_forced(
|
||||
context, 'network', net_data[az_def.AZ_HINTS])
|
||||
az = self.get_obj_az_by_hints(net_data)
|
||||
|
||||
self._ensure_default_security_group(context, tenant_id)
|
||||
@ -1097,6 +1115,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
{'network': {'vlan_transparent': vlt}})
|
||||
|
||||
rollback_network = True
|
||||
|
||||
is_ddi_network = self._is_ddi_supported_on_network(
|
||||
context, created_net['id'])
|
||||
if (is_backend_network and
|
||||
@ -3265,8 +3284,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
# validate the availability zone
|
||||
if az_def.AZ_HINTS in r:
|
||||
self.validate_availability_zones(context, 'router',
|
||||
r[az_def.AZ_HINTS])
|
||||
self._validate_availability_zones_forced(context, 'router',
|
||||
r[az_def.AZ_HINTS])
|
||||
|
||||
gw_info = self._extract_external_gw(context, router, is_extract=True)
|
||||
r['id'] = (r.get('id') or uuidutils.generate_uuid())
|
||||
@ -4360,8 +4379,19 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
result[(az, 'network')] = True
|
||||
return result
|
||||
|
||||
def _validate_availability_zones_forced(self, context, resource_type,
|
||||
availability_zones):
|
||||
return self.validate_availability_zones(context, resource_type,
|
||||
availability_zones,
|
||||
force=True)
|
||||
|
||||
def validate_availability_zones(self, context, resource_type,
|
||||
availability_zones):
|
||||
availability_zones, force=False):
|
||||
# This method is called directly from this plugin but also from
|
||||
# registered callbacks
|
||||
if self._is_sub_plugin and not force:
|
||||
# validation should be done together for both plugins
|
||||
return
|
||||
# If no native_dhcp_metadata - use neutron AZs
|
||||
if not cfg.CONF.nsx_v3.native_dhcp_metadata:
|
||||
return super(NsxV3Plugin, self).validate_availability_zones(
|
||||
|
Loading…
Reference in New Issue
Block a user