NSX|P Availability zones support

For networks & routers

Change-Id: I338147bafdf4e1950db4c2cbb8166c515404d5c1
This commit is contained in:
Adit Sarfaty 2018-12-18 07:26:15 +02:00
parent 1d7e552ef5
commit 5b95817834
12 changed files with 432 additions and 227 deletions

View File

@ -881,7 +881,7 @@ nsxv_az_opts = [
# the list of expected zones is under nsx_v3 group: availability_zones
# Note: if any of the optional arguments is missing - the global one will be
# used instead.
nsxv3_az_opts = [
nsx_v3_and_p_az_opts = [
cfg.StrOpt('metadata_proxy',
help=_("The name or UUID of the NSX Metadata Proxy "
"that will be used to enable native metadata service. "
@ -913,6 +913,13 @@ nsxv3_az_opts = [
"transport zone that will be used for bridging between "
"Neutron networks, if no physical network has been "
"specified")),
cfg.StrOpt('default_tier0_router',
help=_("Name or UUID of the default tier0 router that will be "
"used for connecting to tier1 logical routers and "
"configuring external networks")),
]
nsxv3_az_opts = nsx_v3_and_p_az_opts + [
cfg.ListOpt('switching_profiles',
help=_("(Optional) list switching profiles uuids that will be "
"attached to all neutron created nsx ports.")),
@ -930,6 +937,8 @@ nsxv3_az_opts = [
" the Tier0 router")),
]
nsxp_az_opts = nsx_v3_and_p_az_opts
nsx_tvd_opts = [
cfg.ListOpt('nsx_v_extension_drivers',
default=[],
@ -1009,8 +1018,13 @@ def register_nsxv3_azs(conf, availability_zones):
_register_nsx_azs(conf, availability_zones, nsxv3_az_opts)
def register_nsxp_azs(conf, availability_zones):
_register_nsx_azs(conf, availability_zones, nsxp_az_opts)
register_nsxv_azs(cfg.CONF, cfg.CONF.nsxv.availability_zones)
register_nsxv3_azs(cfg.CONF, cfg.CONF.nsx_v3.availability_zones)
register_nsxp_azs(cfg.CONF, cfg.CONF.nsx_p.availability_zones)
def _get_nsx_az_opts(az, opts):
@ -1034,6 +1048,10 @@ def get_nsxv3_az_opts(az):
return _get_nsx_az_opts(az, nsxv3_az_opts)
def get_nsxp_az_opts(az):
return _get_nsx_az_opts(az, nsxp_az_opts)
def validate_nsxv_config_options():
if (cfg.CONF.nsxv.manager_uri is None or
cfg.CONF.nsxv.user is None or

View File

@ -15,11 +15,8 @@
from vmware_nsx._i18n import _
from vmware_nsx.common import availability_zones as common_az
from vmware_nsx.common import config
from vmware_nsx.common import exceptions as nsx_exc
DEFAULT_NAME = common_az.DEFAULT_NAME + 'v3'
class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone):
@ -34,8 +31,12 @@ class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone):
# May be overriden by children
return True
def get_az_opts(self):
# Should be implemented by children
pass
def init_from_config_section(self, az_name):
az_info = config.get_nsxv3_az_opts(self.name)
az_info = self.get_az_opts()
if self._has_native_dhcp_metadata():
# The optional parameters will get the global values if not

View File

@ -23,14 +23,29 @@ from sqlalchemy import exc as sql_exc
from six import moves
from neutron.db import agentschedulers_db
from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db.availability_zone import router as router_az_db
from neutron.db import dns_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_attrs_db
from neutron.db import l3_db
from neutron.db import l3_gwmode_db
from neutron.db import portbindings_db
from neutron.db import portsecurity_db
from neutron.db import securitygroups_db
from neutron.db import vlantransparent_db
from neutron.extensions import securitygroup as ext_sg
from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
from neutron_lib.api.definitions import availability_zone as az_def
from neutron_lib.api.definitions import external_net as extnet_apidef
from neutron_lib.api.definitions import port_security as psec
from neutron_lib.api.definitions import portbindings as pbin
from neutron_lib.api.definitions import provider_net as pnet
from neutron_lib.api import validators
from neutron_lib.api.validators import availability_zone as az_validator
from neutron_lib import constants
from neutron_lib.db import api as db_api
from neutron_lib.db import utils as db_utils
@ -42,11 +57,14 @@ from neutron_lib.services.qos import constants as qos_consts
from neutron_lib.utils import helpers
from neutron_lib.utils import net as nl_net_utils
from vmware_nsx.common import availability_zones as nsx_com_az
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.common import nsx_constants
from vmware_nsx.common import utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import extended_security_group as extended_sec
from vmware_nsx.db import extended_security_group_rule as extend_sg_rule
from vmware_nsx.db import maclearning as mac_db
from vmware_nsx.db import nsx_portbindings_db as pbin_db
from vmware_nsx.extensions import maclearning as mac_ext
from vmware_nsx.extensions import providersecuritygroup as provider_sg
@ -61,9 +79,31 @@ from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts
LOG = logging.getLogger(__name__)
class NsxPluginV3Base(plugin.NsxPluginBase,
# NOTE(asarfaty): the order of inheritance here is important. in order for the
# QoS notification to work, the AgentScheduler init must be called first
# NOTE(arosen): same is true with the ExtendedSecurityGroupPropertiesMixin
# this needs to be above securitygroups_db.SecurityGroupDbMixin.
# FIXME(arosen): we can solve this inheritance order issue by just mixining in
# the classes into a new class to handle the order correctly.
class NsxPluginV3Base(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
addr_pair_db.AllowedAddressPairsMixin,
plugin.NsxPluginBase,
extended_sec.ExtendedSecurityGroupPropertiesMixin,
pbin_db.NsxPortBindingMixin):
pbin_db.NsxPortBindingMixin,
extend_sg_rule.ExtendedSecurityGroupRuleMixin,
securitygroups_db.SecurityGroupDbMixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
router_az_db.RouterAvailabilityZoneMixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_db.PortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
extradhcpopt_db.ExtraDhcpOptMixin,
dns_db.DNSDbMixin,
vlantransparent_db.Vlantransparent_db_mixin,
mac_db.MacLearningDbMixin,
l3_attrs_db.ExtraAttributesMixin,
nsx_com_az.NSXAvailabilityZonesPluginCommon):
"""Common methods for NSX-V3 plugins (NSX-V3 & Policy)"""
def __init__(self):
@ -1194,3 +1234,88 @@ class NsxPluginV3Base(plugin.NsxPluginBase,
elif not port_security:
return True
return False
def _validate_obj_az_on_creation(self, context, obj_data, obj_type):
# validate the availability zone, and get the AZ object
if az_def.AZ_HINTS in obj_data:
self._validate_availability_zones_forced(
context, obj_type, obj_data[az_def.AZ_HINTS])
return self.get_obj_az_by_hints(obj_data)
def _add_az_to_net(self, context, net_id, net_data):
if az_def.AZ_HINTS in net_data:
# Update the AZ hints in the neutron object
az_hints = az_validator.convert_az_list_to_string(
net_data[az_def.AZ_HINTS])
super(NsxPluginV3Base, self).update_network(
context, net_id,
{'network': {az_def.AZ_HINTS: az_hints}})
def _add_az_to_router(self, context, router_id, router_data):
if az_def.AZ_HINTS in router_data:
# Update the AZ hints in the neutron object
az_hints = az_validator.convert_az_list_to_string(
router_data[az_def.AZ_HINTS])
super(NsxPluginV3Base, self).update_router(
context, router_id,
{'router': {az_def.AZ_HINTS: az_hints}})
def get_network_availability_zones(self, net_db):
if self._has_native_dhcp_metadata():
hints = az_validator.convert_az_string_to_list(
net_db[az_def.AZ_HINTS])
# When using the configured AZs, the az will always be the same
# as the hint (or default if none)
if hints:
az_name = hints[0]
else:
az_name = self.get_default_az().name
return [az_name]
else:
return []
def _get_router_az_obj(self, router):
l3_attrs_db.ExtraAttributesMixin._extend_extra_router_dict(
router, router)
return self.get_router_az(router)
def get_router_availability_zones(self, router):
"""Return availability zones which a router belongs to."""
return [self._get_router_az_obj(router).name]
def _validate_availability_zones_forced(self, context, resource_type,
availability_zones):
return self.validate_availability_zones(context, resource_type,
availability_zones,
force=True)
def _list_availability_zones(self, context, filters=None):
# If no native_dhcp_metadata - use neutron AZs
if not self._has_native_dhcp_metadata():
return super(NsxPluginV3Base, self)._list_availability_zones(
context, filters=filters)
result = {}
for az in self._availability_zones_data.list_availability_zones():
# Add this availability zone as a network & router resource
if filters:
if 'name' in filters and az not in filters['name']:
continue
for res in ['network', 'router']:
if 'resource' not in filters or res in filters['resource']:
result[(az, res)] = True
return result
def validate_availability_zones(self, context, resource_type,
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 self._has_native_dhcp_metadata():
return super(NsxPluginV3Base, self).validate_availability_zones(
context, resource_type, availability_zones)
# Validate against the configured AZs
return self.validate_obj_azs(availability_zones)

View File

@ -14,16 +14,24 @@
# under the License.
from oslo_config import cfg
from oslo_log import log
from vmware_nsx.common import availability_zones as common_az
from vmware_nsx.common import config
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.plugins.common_v3 import availability_zones as v3_az
from vmware_nsxlib.v3 import exceptions as nsx_lib_exc
LOG = log.getLogger(__name__)
DEFAULT_NAME = common_az.DEFAULT_NAME + 'v3'
DEFAULT_NAME = common_az.DEFAULT_NAME + 'p'
class NsxPAvailabilityZone(v3_az.NsxV3AvailabilityZone):
def get_az_opts(self):
return config.get_nsxp_az_opts(self.name)
def init_defaults(self):
# use the default configuration
self.metadata_proxy = cfg.CONF.nsx_p.metadata_proxy
@ -32,6 +40,80 @@ class NsxPAvailabilityZone(v3_az.NsxV3AvailabilityZone):
self.default_overlay_tz = cfg.CONF.nsx_p.default_overlay_tz
self.default_vlan_tz = cfg.CONF.nsx_p.default_vlan_tz
self.default_tier0_router = cfg.CONF.nsx_p.default_tier0_router
self.dns_domain = cfg.CONF.nsx_p.dns_domain
self.nameservers = cfg.CONF.nsx_p.nameservers
def _init_default_resource(self, resource_api, config_name,
filter_list_results=None,
auto_config=False,
is_mandatory=True):
# NOTE(annak): we may need to generalize this for API calls
# requiring path ids
name_or_id = getattr(self, config_name)
if not name_or_id:
if auto_config:
# If the field not specified, the system will auto-configure
# in case only single resource is present
resources = resource_api.list()
if filter_list_results:
resources = filter_list_results(resources)
if len(resources) == 1:
return resources[0]['id']
if is_mandatory:
if self.is_default():
raise cfg.RequiredOptError(config_name,
group=cfg.OptGroup('nsx_p'))
else:
msg = (_("No %(res)s provided for availability "
"zone %(az)s") % {
'res': config_name,
'az': self.name})
raise nsx_exc.NsxPluginException(err_msg=msg)
return None
try:
# Check if the configured value is the ID
resource_api.get(name_or_id, silent=True)
return name_or_id
except nsx_lib_exc.ResourceNotFound:
# Check if the configured value is the name
resource = resource_api.get_by_name(name_or_id)
if resource:
return resource['id']
else:
if self.is_default():
raise cfg.RequiredOptError(config_name,
group=cfg.OptGroup('nsx_p'))
else:
msg = (_("Could not find %(res)s %(id)s for availability "
"zone %(az)s") % {
'res': config_name,
'id': name_or_id,
'az': self.name})
raise nsx_exc.NsxPluginException(err_msg=msg)
def translate_configured_names_to_uuids(self, nsxpolicy):
super(NsxPAvailabilityZone, self).translate_configured_names_to_uuids(
nsxpolicy)
# TODO(asarfaty): add DHCP/metadata parameters
# TODO(asarfaty): add support for init_objects_by_tags
self._default_overlay_tz_uuid = self._init_default_resource(
nsxpolicy.transport_zone, 'default_overlay_tz',
auto_config=True, is_mandatory=True,
filter_list_results=lambda tzs: [
tz for tz in tzs if tz['tz_type'].startswith('OVERLAY')])
self._default_vlan_tz_uuid = self._init_default_resource(
nsxpolicy.transport_zone, 'default_vlan_tz',
auto_config=True, is_mandatory=False,
filter_list_results=lambda tzs: [
tz for tz in tzs if tz['tz_type'].startswith('VLAN')])
self._default_tier0_router = self._init_default_resource(
nsxpolicy.tier0, 'default_tier0_router',
auto_config=True, is_mandatory=True)
class NsxPAvailabilityZones(common_az.ConfiguredAvailabilityZones):

View File

@ -22,22 +22,10 @@ from oslo_utils import excutils
from oslo_utils import uuidutils
import webob.exc
from neutron.db import agentschedulers_db
from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db import dns_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_attrs_db
from neutron.db import l3_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 portbindings_db
from neutron.db import portsecurity_db
from neutron.db import securitygroups_db
from neutron.db import vlantransparent_db
from neutron.extensions import providernet
from neutron.extensions import securitygroup as ext_sg
from neutron.quota import resource_registry
@ -66,8 +54,6 @@ from vmware_nsx.common import locking
from vmware_nsx.common import managers
from vmware_nsx.common import utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import extended_security_group_rule as extend_sg_rule
from vmware_nsx.db import maclearning as mac_db
from vmware_nsx.extensions import maclearning as mac_ext
from vmware_nsx.extensions import projectpluginmap
from vmware_nsx.extensions import providersecuritygroup as provider_sg
@ -105,21 +91,7 @@ SEG_SECURITY_PROFILE_UUID = (
@resource_extend.has_resource_extenders
class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
addr_pair_db.AllowedAddressPairsMixin,
nsx_plugin_common.NsxPluginV3Base,
extend_sg_rule.ExtendedSecurityGroupRuleMixin,
securitygroups_db.SecurityGroupDbMixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_db.PortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
extradhcpopt_db.ExtraDhcpOptMixin,
dns_db.DNSDbMixin,
vlantransparent_db.Vlantransparent_db_mixin,
mac_db.MacLearningDbMixin,
l3_attrs_db.ExtraAttributesMixin):
class NsxPolicyPlugin(nsx_plugin_common.NsxPluginV3Base):
__native_bulk_support = True
__native_pagination_support = True
@ -140,6 +112,9 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
"external-net",
"extraroute",
"router",
"availability_zone",
"network_availability_zone",
"router_availability_zone",
"subnet_allocation",
"security-group-logging",
"provider-security-group",
@ -159,6 +134,7 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
def __init__(self):
self.fwaas_callbacks = None
self.init_is_complete = False
self._is_sub_plugin = False
nsxlib_utils.set_is_attr_callback(validators.is_attr_set)
self._extend_fault_map()
extension_drivers = cfg.CONF.nsx_extension_drivers
@ -189,60 +165,11 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
resources.PROCESS,
events.AFTER_INIT)
# NOTE(annak): we may need to generalize this for API calls
# requiring path ids
def _init_default_resource(self, resource_api, name_or_id,
filter_list_results=None):
if not name_or_id:
# If not specified, the system will auto-configure
# in case only single resource is present
resources = resource_api.list()
if filter_list_results:
resources = filter_list_results(resources)
if len(resources) == 1:
return resources[0]['id']
else:
return None
try:
resource_api.get(name_or_id, silent=True)
return name_or_id
except nsx_lib_exc.ResourceNotFound:
try:
resource = resource_api.get_by_name(name_or_id)
if resource:
return resource['id']
except nsx_lib_exc.ResourceNotFound:
return None
def _init_default_config(self):
"""Validate the configuration & initialize default values"""
# Default Tier0 router
self.default_tier0_router = self._init_default_resource(
self.nsxpolicy.tier0,
cfg.CONF.nsx_p.default_tier0_router)
if not self.default_tier0_router:
raise cfg.RequiredOptError("default_tier0_router",
group=cfg.OptGroup('nsx_p'))
# Default overlay transport zone
self.default_overlay_tz = self._init_default_resource(
self.nsxpolicy.transport_zone,
cfg.CONF.nsx_p.default_overlay_tz,
filter_list_results=lambda tzs: [
tz for tz in tzs if tz['tz_type'].startswith('OVERLAY')])
if not self.default_overlay_tz:
raise cfg.RequiredOptError("default_overlay_tz",
group=cfg.OptGroup('nsx_p'))
# Default VLAN transport zone (not mandatory)
self.default_vlan_tz = self._init_default_resource(
self.nsxpolicy.transport_zone,
cfg.CONF.nsx_p.default_vlan_tz,
filter_list_results=lambda tzs: [
tz for tz in tzs if tz['tz_type'].startswith('VLAN')])
# Default tier0/transport zones are initialized via the default AZ
# Init AZ resources
for az in self.get_azs_list():
az.translate_configured_names_to_uuids(self.nsxpolicy)
def init_availability_zones(self):
self._availability_zones_data = nsxp_az.NsxPAvailabilityZones()
@ -419,6 +346,9 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
is_external_net = validators.is_attr_set(external) and external
tenant_id = net_data['tenant_id']
# validate the availability zone, and get the AZ object
az = self._validate_obj_az_on_creation(context, net_data, 'network')
self._ensure_default_security_group(context, tenant_id)
vlt = vlan_apidef.get_vlan_transparent(net_data)
@ -427,7 +357,7 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
if is_external_net:
is_provider_net, net_type, physical_net, vlan_id = (
self._validate_external_net_create(
net_data, self.default_tier0_router,
net_data, az._default_tier0_router,
self._tier0_validator))
provider_data = {'is_provider_net': is_provider_net,
'net_type': net_type,
@ -437,8 +367,8 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
else:
provider_data = self._validate_provider_create(
context, net_data,
self.default_vlan_tz,
self.default_overlay_tz,
az._default_vlan_tz_uuid,
az._default_overlay_tz_uuid,
self.nsxpolicy.transport_zone,
self.nsxpolicy.segment,
transparent_vlan=vlt)
@ -464,6 +394,7 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
self._process_network_port_security_create(
context, net_data, created_net)
self._process_l3_create(context, created_net, net_data)
self._add_az_to_net(context, created_net['id'], net_data)
if provider_data['is_provider_net']:
# Save provider network fields, needed by get_network()
@ -942,7 +873,8 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
return
network = self.get_network(context, network_id)
if not network.get(pnet.PHYSICAL_NETWORK):
return self.default_tier0_router
az = self.get_network_az(network)
return az._default_tier0_router
else:
return network.get(pnet.PHYSICAL_NETWORK)
@ -1104,6 +1036,11 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
def create_router(self, context, router):
r = router['router']
gw_info = self._extract_external_gw(context, router, is_extract=True)
# validate the availability zone, and get the AZ object
# TODO(asarfaty): router AZ is not used for anything yet
self._validate_obj_az_on_creation(context, r, 'router')
with db_api.CONTEXT_WRITER.using(context):
router = super(NsxPolicyPlugin, self).create_router(
context, router)
@ -1917,9 +1854,6 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
tz)
return type == nsxlib_consts.TRANSPORT_TYPE_OVERLAY
def _has_native_dhcp_metadata(self):
return True
def _is_ens_tz_net(self, context, net_id):
#TODO(annak): handle ENS case
return False
@ -1927,3 +1861,6 @@ class NsxPolicyPlugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
def _is_ens_tz_port(self, context, port_data):
#TODO(annak): handle ENS case
return False
def _has_native_dhcp_metadata(self):
return True

View File

@ -21,16 +21,21 @@ from vmware_nsx.plugins.common_v3 import availability_zones as v3_az
from vmware_nsxlib.v3 import core_resources
from vmware_nsxlib.v3 import nsx_constants as nsxlib_consts
DEFAULT_NAME = common_az.DEFAULT_NAME + 'v3'
class NsxV3AvailabilityZone(v3_az.NsxV3AvailabilityZone):
def get_az_opts(self):
return config.get_nsxv3_az_opts(self.name)
def _has_native_dhcp_metadata(self):
return cfg.CONF.nsx_v3.native_dhcp_metadata
def init_from_config_section(self, az_name):
super(NsxV3AvailabilityZone, self).init_from_config_section(az_name)
az_info = config.get_nsxv3_az_opts(self.name)
az_info = self.get_az_opts()
switching_profiles = az_info.get('switching_profiles')
if switching_profiles:
@ -197,7 +202,7 @@ class NsxV3AvailabilityZone(v3_az.NsxV3AvailabilityZone):
class NsxV3AvailabilityZones(common_az.ConfiguredAvailabilityZones):
default_name = v3_az.DEFAULT_NAME
default_name = DEFAULT_NAME
def __init__(self, use_tvd_config=False):
if use_tvd_config:

View File

@ -19,13 +19,11 @@ import mock
import netaddr
from neutron_lib.agent import topics
from neutron_lib.api.definitions import allowedaddresspairs as addr_apidef
from neutron_lib.api.definitions import availability_zone as az_def
from neutron_lib.api.definitions import external_net as extnet_apidef
from neutron_lib.api.definitions import l3 as l3_apidef
from neutron_lib.api.definitions import port_security as psec
from neutron_lib.api import extensions
from neutron_lib.api import faults
from neutron_lib.api.validators import availability_zone as az_validator
from neutron_lib.db import api as db_api
from neutron_lib.db import resource_extend
from neutron_lib.db import utils as db_utils
@ -39,24 +37,11 @@ from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api
from neutron.api.rpc.handlers import dhcp_rpc
from neutron.api.rpc.handlers import metadata_rpc
from neutron.db import agents_db
from neutron.db import agentschedulers_db
from neutron.db import allowedaddresspairs_db as addr_pair_db
from neutron.db.availability_zone import router as router_az_db
from neutron.db import db_base_plugin_v2
from neutron.db import dns_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_attrs_db
from neutron.db import l3_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 portbindings_db
from neutron.db import portsecurity_db
from neutron.db import securitygroups_db
from neutron.db import vlantransparent_db
from neutron.extensions import providernet
from neutron.extensions import securitygroup as ext_sg
from neutron.quota import resource_registry
@ -82,7 +67,6 @@ import webob.exc
from vmware_nsx._i18n import _
from vmware_nsx.api_replay import utils as api_replay_utils
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 l3_rpc_agent_api
@ -91,8 +75,6 @@ from vmware_nsx.common import managers
from vmware_nsx.common import nsx_constants
from vmware_nsx.common import utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.db import extended_security_group_rule as extend_sg_rule
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 housekeeper as hk_ext
@ -145,30 +127,8 @@ NSX_V3_CLIENT_SSL_PROFILE = 'nsx-default-client-ssl-profile'
NSX_V3_OS_DFW_UUID = '00000000-def0-0000-0fed-000000000000'
# NOTE(asarfaty): the order of inheritance here is important. in order for the
# QoS notification to work, the AgentScheduler init must be called first
# NOTE(arosen): same is true with the ExtendedSecurityGroupPropertiesMixin
# this needs to be above securitygroups_db.SecurityGroupDbMixin.
# FIXME(arosen): we can solve this inheritance order issue by just mixining in
# the classes into a new class to handle the order correctly.
@resource_extend.has_resource_extenders
class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
addr_pair_db.AllowedAddressPairsMixin,
nsx_plugin_common.NsxPluginV3Base,
extend_sg_rule.ExtendedSecurityGroupRuleMixin,
securitygroups_db.SecurityGroupDbMixin,
external_net_db.External_net_db_mixin,
extraroute_db.ExtraRoute_db_mixin,
router_az_db.RouterAvailabilityZoneMixin,
l3_gwmode_db.L3_NAT_db_mixin,
portbindings_db.PortBindingMixin,
portsecurity_db.PortSecurityDbMixin,
extradhcpopt_db.ExtraDhcpOptMixin,
dns_db.DNSDbMixin,
vlantransparent_db.Vlantransparent_db_mixin,
mac_db.MacLearningDbMixin,
nsx_com_az.NSXAvailabilityZonesPluginCommon,
l3_attrs_db.ExtraAttributesMixin,
class NsxV3Plugin(nsx_plugin_common.NsxPluginV3Base,
hk_ext.Housekeeper):
__native_bulk_support = True
@ -879,11 +839,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
return self.conn.consume_in_threads()
def _get_router_az_obj(self, router):
l3_attrs_db.ExtraAttributesMixin._extend_extra_router_dict(
router, router)
return self.get_router_az(router)
def _get_edge_cluster(self, tier0_uuid, router):
az = self._get_router_az_obj(router)
if az and az._edge_cluster_uuid:
@ -1046,10 +1001,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
tenant_id = net_data['tenant_id']
# validate the availability zone, and get the AZ object
if az_def.AZ_HINTS in net_data:
self._validate_availability_zones_forced(
context, 'network', net_data[az_def.AZ_HINTS])
az = self.get_obj_az_by_hints(net_data)
az = self._validate_obj_az_on_creation(context, net_data, 'network')
self._ensure_default_security_group(context, tenant_id)
@ -1086,15 +1038,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
self._process_network_port_security_create(
context, net_data, created_net)
self._process_l3_create(context, created_net, net_data)
if az_def.AZ_HINTS in net_data:
# Update the AZ hints in the neutron object
az_hints = az_validator.convert_az_list_to_string(
net_data[az_def.AZ_HINTS])
super(NsxV3Plugin, self).update_network(
context,
created_net['id'],
{'network': {az_def.AZ_HINTS: az_hints}})
self._add_az_to_net(context, created_net['id'], net_data)
if is_provider_net:
# Save provider network fields, needed by get_network()
@ -3004,7 +2948,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
return
network = self.get_network(context, network_id)
if not network.get(pnet.PHYSICAL_NETWORK):
az = self.get_network_az_by_net_id(context, network_id)
az = self.get_network_az(network)
return az._default_tier0_router
else:
return network.get(pnet.PHYSICAL_NETWORK)
@ -3221,9 +3165,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
self.validate_router_dhcp_relay(context)
# validate the availability zone
if az_def.AZ_HINTS in r:
self._validate_availability_zones_forced(context, 'router',
r[az_def.AZ_HINTS])
self._validate_obj_az_on_creation(context, r, 'router')
gw_info = self._extract_external_gw(context, router, is_extract=True)
r['id'] = (r.get('id') or uuidutils.generate_uuid())
@ -3231,14 +3173,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
r, resource_type='os-neutron-router-id',
project_name=context.tenant_name)
router = super(NsxV3Plugin, self).create_router(context, router)
if az_def.AZ_HINTS in r:
# Update the AZ hints in the neutron object
az_hints = az_validator.convert_az_list_to_string(
r[az_def.AZ_HINTS])
super(NsxV3Plugin, self).update_router(
context,
router['id'],
{'router': {az_def.AZ_HINTS: az_hints}})
self._add_az_to_router(context, router['id'], r)
router_db = self._get_router(context, r['id'])
with db_api.CONTEXT_WRITER.using(context):
self._process_extra_attr_router_create(context, router_db, r)
@ -3319,10 +3255,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
return ret_val
def get_router_availability_zones(self, router):
"""Return availability zones which a router belongs to."""
return [self._get_router_az_obj(router).name]
def _update_router_wrapper(self, context, router_id, router):
if cfg.CONF.api_replay_mode:
# NOTE(arosen): the mock.patch here is needed for api_replay_mode
@ -4325,57 +4257,6 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
rules = [(rule['display_name'], rule['id']) for rule in firewall_rules]
nsx_db.save_sg_rule_mappings(context.session, rules)
def _list_availability_zones(self, context, filters=None):
# If no native_dhcp_metadata - use neutron AZs
if not cfg.CONF.nsx_v3.native_dhcp_metadata:
return super(NsxV3Plugin, self)._list_availability_zones(
context, filters=filters)
result = {}
for az in self._availability_zones_data.list_availability_zones():
# Add this availability zone as a network & router resource
if filters:
if 'name' in filters and az not in filters['name']:
continue
for res in ['network', 'router']:
if 'resource' not in filters or res in filters['resource']:
result[(az, res)] = 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, 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(
context, resource_type, availability_zones)
# Validate against the configured AZs
return self.validate_obj_azs(availability_zones)
def get_network_availability_zones(self, net_db):
if cfg.CONF.nsx_v3.native_dhcp_metadata:
hints = az_validator.convert_az_string_to_list(
net_db[az_def.AZ_HINTS])
# When using the configured AZs, the az will always be the same
# as the hint (or default if none)
if hints:
az_name = hints[0]
else:
az_name = self.get_default_az().name
return [az_name]
else:
return []
def recalculate_snat_rules_for_router(self, context, router, subnets):
"""Recalculate router snat rules for specific subnets.
Invoked when subnetpool address scope changes.

View File

@ -12,12 +12,15 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from neutron.db import l3_dvr_db # noqa
from neutron_lib import context
from neutron_lib.plugins import constants as const
from neutron_lib.plugins import directory
from oslo_log import log as logging
from vmware_nsx.common import config
from vmware_nsx.plugins.nsx_p import plugin
from vmware_nsx.plugins.nsx_v3 import utils as v3_utils
from vmware_nsx.shell.admin.plugins.common import formatters
@ -70,6 +73,8 @@ def get_realization_info(resource, *realization_args):
class NsxPolicyPluginWrapper(plugin.NsxPolicyPlugin):
def __init__(self):
# initialize the availability zones
config.register_nsxp_azs(cfg.CONF, cfg.CONF.nsx_p.availability_zones)
super(NsxPolicyPluginWrapper, self).__init__()
self.context = context.get_admin_context()

View File

@ -24,7 +24,7 @@ from oslo_log import log as logging
from vmware_nsx.common import config # noqa
from vmware_nsx.common import utils as nsx_utils
from vmware_nsx.dhcp_meta import rpc as nsx_rpc
from vmware_nsx.plugins.common_v3 import availability_zones as nsx_az
from vmware_nsx.plugins.nsx_v3 import availability_zones as nsx_az
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

View File

@ -0,0 +1,129 @@
# Copyright 2018 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
from oslo_utils import uuidutils
from neutron.tests import base
from vmware_nsx.common import config
from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.plugins.nsx_p import availability_zones as nsx_az
class NsxPAvailabilityZonesTestCase(base.BaseTestCase):
def setUp(self):
super(NsxPAvailabilityZonesTestCase, self).setUp()
self.az_name = "zone1"
self.group_name = "az:%s" % self.az_name
config.register_nsxv3_azs(cfg.CONF, [self.az_name])
self.global_md_proxy = uuidutils.generate_uuid()
cfg.CONF.set_override(
"metadata_proxy", self.global_md_proxy, group="nsx_p")
self.global_dhcp_profile = uuidutils.generate_uuid()
cfg.CONF.set_override(
"dhcp_profile", self.global_dhcp_profile, group="nsx_p")
cfg.CONF.set_override(
"native_metadata_route", "1.1.1.1", group="nsx_p")
cfg.CONF.set_override("dns_domain", "xxx.com", group="nsx_p")
cfg.CONF.set_override("nameservers", ["10.1.1.1"], group="nsx_p")
cfg.CONF.set_override(
"default_tier0_router", "uuidrtr1", group="nsx_p")
def _config_az(self,
metadata_proxy="metadata_proxy1",
dhcp_profile="dhcp_profile1",
native_metadata_route="2.2.2.2",
dns_domain="aaa.com",
nameservers=["20.1.1.1"],
default_overlay_tz='otz',
default_vlan_tz='vtz',
default_tier0_router="uuidrtr2"):
if metadata_proxy is not None:
cfg.CONF.set_override("metadata_proxy", metadata_proxy,
group=self.group_name)
if dhcp_profile is not None:
cfg.CONF.set_override("dhcp_profile", dhcp_profile,
group=self.group_name)
if native_metadata_route is not None:
cfg.CONF.set_override("native_metadata_route",
native_metadata_route,
group=self.group_name)
if dns_domain is not None:
cfg.CONF.set_override("dns_domain", dns_domain,
group=self.group_name)
if nameservers is not None:
cfg.CONF.set_override("nameservers", nameservers,
group=self.group_name)
if default_overlay_tz is not None:
cfg.CONF.set_override("default_overlay_tz", default_overlay_tz,
group=self.group_name)
if default_vlan_tz is not None:
cfg.CONF.set_override("default_vlan_tz", default_vlan_tz,
group=self.group_name)
if default_tier0_router is not None:
cfg.CONF.set_override("default_tier0_router", default_tier0_router,
group=self.group_name)
def test_simple_availability_zone(self):
self._config_az()
az = nsx_az.NsxPAvailabilityZone(self.az_name)
self.assertEqual(self.az_name, az.name)
self.assertEqual("metadata_proxy1", az.metadata_proxy)
self.assertEqual("dhcp_profile1", az.dhcp_profile)
self.assertEqual("2.2.2.2", az.native_metadata_route)
self.assertEqual("aaa.com", az.dns_domain)
self.assertEqual(["20.1.1.1"], az.nameservers)
self.assertEqual("otz", az.default_overlay_tz)
self.assertEqual("vtz", az.default_vlan_tz)
self.assertEqual("uuidrtr2", az.default_tier0_router)
def test_missing_group_section(self):
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.NsxPAvailabilityZone,
"doesnt_exist")
def test_availability_zone_missing_metadata_proxy(self):
# Mandatory parameter
self._config_az(metadata_proxy=None)
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.NsxPAvailabilityZone,
self.az_name)
def test_availability_zone_missing_dhcp_profile(self):
# Mandatory parameter
self._config_az(dhcp_profile=None)
self.assertRaises(
nsx_exc.NsxInvalidConfiguration,
nsx_az.NsxPAvailabilityZone,
self.az_name)
def test_availability_zone_missing_md_route(self):
self._config_az(native_metadata_route=None)
az = nsx_az.NsxPAvailabilityZone(self.az_name)
self.assertEqual("1.1.1.1", az.native_metadata_route)
def test_availability_zone_missing_dns_domain(self):
self._config_az(dns_domain=None)
az = nsx_az.NsxPAvailabilityZone(self.az_name)
self.assertEqual("xxx.com", az.dns_domain)
def test_availability_zone_missing_nameservers(self):
self._config_az(nameservers=None)
az = nsx_az.NsxPAvailabilityZone(self.az_name)
self.assertEqual(["10.1.1.1"], az.nameservers)

View File

@ -44,6 +44,7 @@ from neutron_lib import exceptions as n_exc
from neutron_lib.plugins import directory
from vmware_nsx.common import utils
from vmware_nsx.plugins.nsx_p import plugin as nsx_plugin
from vmware_nsx.tests import unit as vmware
from vmware_nsx.tests.unit.common_plugin import common_v3
from vmware_nsxlib.v3 import exceptions as nsxlib_exc
@ -362,6 +363,17 @@ class NsxPTestNetworks(test_db_base_plugin_v2.TestNetworksV2,
self.assertEqual('InvalidInput',
res['NeutronError']['type'])
@mock.patch.object(nsx_plugin.NsxPolicyPlugin,
'validate_availability_zones')
def test_create_network_with_availability_zone(self, mock_validate_az):
name = 'net-with-zone'
zone = ['zone1']
mock_validate_az.return_value = None
with self.network(name=name, availability_zone_hints=zone) as net:
az_hints = net['network']['availability_zone_hints']
self.assertListEqual(az_hints, zone)
class NsxPTestPorts(test_db_base_plugin_v2.TestPortsV2,
NsxPPluginTestCaseMixin):
@ -1140,3 +1152,13 @@ class NsxPTestL3NatTestCase(NsxPTestL3NatTest,
body = self._show('routers', r['router']['id'])
gw_info = body['router']['external_gateway_info']
self.assertIsNone(gw_info)
@mock.patch.object(nsx_plugin.NsxPolicyPlugin,
'validate_availability_zones')
def test_create_router_with_availability_zone(self, mock_validate_az):
name = 'rtr-with-zone'
zone = ['zone1']
mock_validate_az.return_value = None
with self.router(name=name, availability_zone_hints=zone) as rtr:
az_hints = rtr['router']['availability_zone_hints']
self.assertListEqual(zone, az_hints)

View File

@ -31,7 +31,7 @@ from vmware_nsx.common import exceptions as nsx_exc
from vmware_nsx.common import utils
from vmware_nsx.db import db as nsx_db
from vmware_nsx.extensions import advancedserviceproviders as as_providers
from vmware_nsx.plugins.common_v3 import availability_zones as nsx_az
from vmware_nsx.plugins.nsx_v3 import availability_zones as nsx_az
from vmware_nsx.tests.unit.nsx_v3 import test_plugin
from vmware_nsxlib.v3 import core_resources
from vmware_nsxlib.v3 import nsx_constants