NSX-V3| network availability zones support
Adding availability zones for nsx-v3 for native dhcp parameters configuration: [nsx_v3] availability_zones = zone1,zone2,zone3 [az:zone1] metadata_proxy = a87d92f3-0106-47dc-a494-de68345fecc8 <profile-name-or-uuid, mandatory> dhcp_profile = 8a4fb2ca-60aa-4291-aab8-d0d6b7790292 profile-name-or-uuid <mandatory> native_metadata_route = 179.254.169.254/31 <optional> dns_domain = aaa.com <optional> nameservers = 1.1.1.1, 2.2.2.2 <optional> Change-Id: I006d922908d5a061480f43eeb92d373fcb4db616
This commit is contained in:
parent
58f3691bcd
commit
84be0ea6a5
@ -0,0 +1,9 @@
|
||||
---
|
||||
prelude: >
|
||||
The NSX-v3 plugin supports availability zones hints on networks
|
||||
creation in order to separate the native dhcp configuration.
|
||||
features:
|
||||
- The NSX-v3 plugin supports availability zones hints on networks
|
||||
creation in order to separate the native dhcp configuration.
|
||||
The availability zones configuration includes the metadata_proxy,
|
||||
dhcp_profile, native_metadata_route and dns related parameters.
|
@ -153,11 +153,7 @@ class NSXAvailabilityZonesPluginCommon(object):
|
||||
|
||||
def get_obj_az_by_hints(self, obj):
|
||||
if az_ext.AZ_HINTS in obj:
|
||||
hints = obj[az_ext.AZ_HINTS]
|
||||
# if this is a string and not a list - need to convert it
|
||||
if not isinstance(hints, list):
|
||||
hints = az_ext.convert_az_string_to_list(hints)
|
||||
for hint in hints:
|
||||
for hint in obj[az_ext.AZ_HINTS]:
|
||||
# For now we use only the first hint
|
||||
return self.get_az_by_hint(hint)
|
||||
|
||||
|
@ -416,6 +416,12 @@ nsx_v3_opts = [
|
||||
default=False,
|
||||
help=_("(Optional) Indicates whether distributed-firewall "
|
||||
"security-groups rules are logged.")),
|
||||
cfg.ListOpt('availability_zones',
|
||||
default=[],
|
||||
help=_('Optional parameter defining the networks availability '
|
||||
'zones names for the native dhcp configuration. The '
|
||||
'configuration of each zone will be under a group '
|
||||
'names [az:<name>]')),
|
||||
]
|
||||
|
||||
DEFAULT_STATUS_CHECK_INTERVAL = 2000
|
||||
@ -668,8 +674,8 @@ nsxv_opts = [
|
||||
help=_("(Optional) Have exclusive DHCP edge per network.")),
|
||||
]
|
||||
|
||||
# define the configuration of each availability zone.
|
||||
# the list of expected zones in under nsxv group: availability_zones
|
||||
# define the configuration of each NSX-V availability zone.
|
||||
# the list of expected zones is under nsxv group: availability_zones
|
||||
# Note: if any of the optional arguments is missing - the global one will be
|
||||
# used instead.
|
||||
nsxv_az_opts = [
|
||||
@ -726,6 +732,32 @@ nsxv_az_opts = [
|
||||
help=_("(Optional) Have exclusive DHCP edge per network.")),
|
||||
]
|
||||
|
||||
# define the configuration of each NSX-V3 availability zone.
|
||||
# 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 = [
|
||||
cfg.StrOpt('metadata_proxy',
|
||||
help=_("The name or UUID of the NSX Metadata Proxy "
|
||||
"that will be used to enable native metadata service. "
|
||||
"It needs to be created in NSX before starting Neutron "
|
||||
"with the NSX plugin.")),
|
||||
cfg.StrOpt('dhcp_profile',
|
||||
help=_("The name or UUID of the NSX DHCP Profile "
|
||||
"that will be used to enable native DHCP service. It "
|
||||
"needs to be created in NSX before starting Neutron "
|
||||
"with the NSX plugin")),
|
||||
cfg.StrOpt('native_metadata_route',
|
||||
help=_("(Optional) The metadata route used for native metadata "
|
||||
"proxy service.")),
|
||||
cfg.StrOpt('dns_domain',
|
||||
help=_("(Optional) Domain to use for building the hostnames.")),
|
||||
cfg.ListOpt('nameservers',
|
||||
help=_("(Optional) List of nameservers to configure for the "
|
||||
"DHCP binding entries. These will be used if there are "
|
||||
"no nameservers defined on the subnet.")),
|
||||
]
|
||||
|
||||
# Register the configuration options
|
||||
cfg.CONF.register_opts(connection_opts)
|
||||
cfg.CONF.register_opts(cluster_opts)
|
||||
@ -740,8 +772,7 @@ cfg.CONF.register_opts(sync_opts, group="NSX_SYNC")
|
||||
cfg.CONF.register_opts(l3_hamode_db.L3_HA_OPTS)
|
||||
|
||||
|
||||
# register a group for each nsxv availability zones
|
||||
def register_nsxv_azs(conf, availability_zones):
|
||||
def _register_nsx_azs(conf, availability_zones, az_opts):
|
||||
# first verify that the availability zones are in the format of a
|
||||
# list of names. The old format was a list of values for each az,
|
||||
# separated with ':'
|
||||
@ -753,13 +784,23 @@ def register_nsxv_azs(conf, availability_zones):
|
||||
conf.register_group(cfg.OptGroup(
|
||||
name=az_group,
|
||||
title="Configuration for availability zone %s" % az))
|
||||
conf.register_opts(nsxv_az_opts, group=az_group)
|
||||
conf.register_opts(az_opts, group=az_group)
|
||||
|
||||
|
||||
# register a group for each nsxv/v3 availability zones
|
||||
def register_nsxv_azs(conf, availability_zones):
|
||||
_register_nsx_azs(conf, availability_zones, nsxv_az_opts)
|
||||
|
||||
|
||||
def register_nsxv3_azs(conf, availability_zones):
|
||||
_register_nsx_azs(conf, availability_zones, nsxv3_az_opts)
|
||||
|
||||
|
||||
register_nsxv_azs(cfg.CONF, cfg.CONF.nsxv.availability_zones)
|
||||
register_nsxv3_azs(cfg.CONF, cfg.CONF.nsx_v3.availability_zones)
|
||||
|
||||
|
||||
def get_nsxv_az_opts(az):
|
||||
def _get_nsx_az_opts(az, opts):
|
||||
az_info = dict()
|
||||
group = 'az:%s' % az
|
||||
if group not in cfg.CONF:
|
||||
@ -767,11 +808,19 @@ def get_nsxv_az_opts(az):
|
||||
opt_name=group,
|
||||
opt_value='None',
|
||||
reason=(_("Configuration group \'%s\' must be defined") % group))
|
||||
for opt in nsxv_az_opts:
|
||||
for opt in opts:
|
||||
az_info[opt.name] = cfg.CONF[group][opt.name]
|
||||
return az_info
|
||||
|
||||
|
||||
def get_nsxv_az_opts(az):
|
||||
return _get_nsx_az_opts(az, nsxv_az_opts)
|
||||
|
||||
|
||||
def get_nsxv3_az_opts(az):
|
||||
return _get_nsx_az_opts(az, nsxv3_az_opts)
|
||||
|
||||
|
||||
def validate_nsxv_config_options():
|
||||
if (cfg.CONF.nsxv.manager_uri is None or
|
||||
cfg.CONF.nsxv.user is None or
|
||||
|
@ -15,10 +15,12 @@
|
||||
# under the License.
|
||||
|
||||
from neutron_lib.api import validators
|
||||
from neutron_lib import context as n_context
|
||||
from neutron_lib.plugins import directory
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log as logging
|
||||
|
||||
from neutron.extensions import availability_zone as az_ext
|
||||
from neutron.extensions import dns
|
||||
from neutron.objects import network as net_obj
|
||||
from neutron.objects import ports as port_obj
|
||||
@ -26,11 +28,13 @@ from neutron.services.externaldns import driver
|
||||
|
||||
from vmware_nsx._i18n import _LE, _LI
|
||||
from vmware_nsx.common import driver_api
|
||||
from vmware_nsx.plugins.nsx_v3 import availability_zones as nsx_az
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
DNS_DOMAIN_DEFAULT = 'openstacklocal.'
|
||||
|
||||
|
||||
# TODO(asarfaty) use dns-domain/nameserver from network az instead of global
|
||||
class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
_supported_extension_alias = 'dns-integration'
|
||||
|
||||
@ -80,7 +84,7 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
if not request_data.get(dns.DNSNAME):
|
||||
return
|
||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data)
|
||||
request_data, db_data['network_id'])
|
||||
if is_dns_domain_default:
|
||||
return
|
||||
network = self._get_network(plugin_context, db_data['network_id'])
|
||||
@ -143,7 +147,7 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
return
|
||||
if dns_name is not None:
|
||||
dns_name, is_dns_domain_default = self._get_request_dns_name(
|
||||
request_data)
|
||||
request_data, db_data['network_id'])
|
||||
if is_dns_domain_default:
|
||||
self._extend_port_dict(plugin_context.session, db_data,
|
||||
db_data, None)
|
||||
@ -198,31 +202,31 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
response_data[dns.DNSDOMAIN] = db_data.dns_domain[dns.DNSDOMAIN]
|
||||
return response_data
|
||||
|
||||
def _get_dns_domain(self):
|
||||
def _get_dns_domain(self, network_id):
|
||||
if not cfg.CONF.dns_domain:
|
||||
return ''
|
||||
if cfg.CONF.dns_domain.endswith('.'):
|
||||
return cfg.CONF.dns_domain
|
||||
return '%s.' % cfg.CONF.dns_domain
|
||||
|
||||
def _get_request_dns_name(self, port):
|
||||
dns_domain = self._get_dns_domain()
|
||||
def _get_request_dns_name(self, port, network_id):
|
||||
dns_domain = self._get_dns_domain(network_id)
|
||||
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
||||
return (port.get(dns.DNSNAME, ''), False)
|
||||
return ('', True)
|
||||
|
||||
def _get_request_dns_name_and_domain_name(self, dns_data_db):
|
||||
dns_domain = self._get_dns_domain()
|
||||
def _get_request_dns_name_and_domain_name(self, dns_data_db, network_id):
|
||||
dns_domain = self._get_dns_domain(network_id)
|
||||
dns_name = ''
|
||||
if ((dns_domain and dns_domain != DNS_DOMAIN_DEFAULT)):
|
||||
if dns_data_db:
|
||||
dns_name = dns_data_db.dns_name
|
||||
return dns_name, dns_domain
|
||||
|
||||
def _get_dns_names_for_port(self, ips, dns_data_db):
|
||||
def _get_dns_names_for_port(self, ips, dns_data_db, network_id):
|
||||
dns_assignment = []
|
||||
dns_name, dns_domain = self._get_request_dns_name_and_domain_name(
|
||||
dns_data_db)
|
||||
dns_data_db, network_id)
|
||||
for ip in ips:
|
||||
if dns_name:
|
||||
hostname = dns_name
|
||||
@ -242,7 +246,8 @@ class DNSExtensionDriver(driver_api.ExtensionDriver):
|
||||
|
||||
def _get_dns_name_for_port_get(self, port, dns_data_db):
|
||||
if port['fixed_ips']:
|
||||
return self._get_dns_names_for_port(port['fixed_ips'], dns_data_db)
|
||||
return self._get_dns_names_for_port(
|
||||
port['fixed_ips'], dns_data_db, port['network_id'])
|
||||
return []
|
||||
|
||||
def _extend_port_dict(self, session, db_data, response_data, dns_data_db):
|
||||
@ -281,10 +286,24 @@ class DNSExtensionDriverNSXv(DNSExtensionDriver):
|
||||
class DNSExtensionDriverNSXv3(DNSExtensionDriver):
|
||||
|
||||
def initialize(self):
|
||||
self._availability_zones = nsx_az.NsxV3AvailabilityZones()
|
||||
LOG.info(_LI("DNSExtensionDriverNSXv3 initialization complete"))
|
||||
|
||||
def _get_dns_domain(self):
|
||||
if cfg.CONF.nsx_v3.dns_domain:
|
||||
def _get_network_az(self, network_id):
|
||||
context = n_context.get_admin_context()
|
||||
network = self._get_network(context, network_id)
|
||||
if az_ext.AZ_HINTS in network and network[az_ext.AZ_HINTS]:
|
||||
az_name = network[az_ext.AZ_HINTS][0]
|
||||
return self._availability_zones.get_availability_zone(az_name)
|
||||
return self._availability_zones.get_default_availability_zone()
|
||||
|
||||
def _get_dns_domain(self, network_id):
|
||||
# try to get the dns-domain from the specific availability zone
|
||||
# of this network
|
||||
az = self._get_network_az(network_id)
|
||||
if az.dns_domain:
|
||||
dns_domain = az.dns_domain
|
||||
elif cfg.CONF.nsx_v3.dns_domain:
|
||||
dns_domain = cfg.CONF.nsx_v3.dns_domain
|
||||
elif cfg.CONF.dns_domain:
|
||||
dns_domain = cfg.CONF.dns_domain
|
||||
|
92
vmware_nsx/plugins/nsx_v3/availability_zones.py
Normal file
92
vmware_nsx/plugins/nsx_v3/availability_zones.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright 2017 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 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
|
||||
|
||||
|
||||
class NsxV3AvailabilityZone(common_az.ConfiguredAvailabilityZone):
|
||||
|
||||
def init_from_config_line(self, config_line):
|
||||
# Not supported for nsx_v3 (old configuration)
|
||||
raise nsx_exc.NsxInvalidConfiguration(
|
||||
opt_name="availability_zones",
|
||||
opt_value=config_line,
|
||||
reason=_("Expected a list of names"))
|
||||
|
||||
def init_from_config_section(self, az_name):
|
||||
az_info = config.get_nsxv3_az_opts(self.name)
|
||||
|
||||
# The optional parameters will get the global values if not
|
||||
# defined for this AZ
|
||||
self.metadata_proxy = az_info.get('metadata_proxy')
|
||||
if not self.metadata_proxy:
|
||||
raise nsx_exc.NsxInvalidConfiguration(
|
||||
opt_name="metadata_proxy",
|
||||
opt_value='None',
|
||||
reason=(_("metadata_proxy for availability zone %s "
|
||||
"must be defined") % az_name))
|
||||
|
||||
self.dhcp_profile = az_info.get('dhcp_profile')
|
||||
if not self.dhcp_profile:
|
||||
raise nsx_exc.NsxInvalidConfiguration(
|
||||
opt_name="dhcp_profile",
|
||||
opt_value='None',
|
||||
reason=(_("dhcp_profile for availability zone %s "
|
||||
"must be defined") % az_name))
|
||||
|
||||
self.native_metadata_route = az_info.get('native_metadata_route')
|
||||
if self.native_metadata_route is None:
|
||||
self.native_metadata_route = cfg.CONF.nsx_v3.native_metadata_route
|
||||
|
||||
self.dns_domain = az_info.get('dns_domain')
|
||||
if self.dns_domain is None:
|
||||
self.dns_domain = cfg.CONF.nsx_v3.dns_domain
|
||||
|
||||
self.nameservers = az_info.get('nameservers')
|
||||
if self.nameservers is None:
|
||||
self.nameservers = cfg.CONF.nsx_v3.nameservers
|
||||
|
||||
def init_default_az(self):
|
||||
# use the default configuration
|
||||
self.metadata_proxy = cfg.CONF.nsx_v3.metadata_proxy
|
||||
self.dhcp_profile = cfg.CONF.nsx_v3.dhcp_profile
|
||||
self.native_metadata_route = cfg.CONF.nsx_v3.native_metadata_route
|
||||
self.dns_domain = cfg.CONF.nsx_v3.dns_domain
|
||||
self.nameservers = cfg.CONF.nsx_v3.nameservers
|
||||
|
||||
def translate_configured_names_to_uuids(self, nsxlib):
|
||||
dhcp_id = nsxlib.native_dhcp_profile.get_id_by_name_or_id(
|
||||
self.dhcp_profile)
|
||||
self._native_dhcp_profile_uuid = dhcp_id
|
||||
|
||||
proxy_id = nsxlib.native_md_proxy.get_id_by_name_or_id(
|
||||
self.metadata_proxy)
|
||||
self._native_md_proxy_uuid = proxy_id
|
||||
|
||||
|
||||
class NsxV3AvailabilityZones(common_az.ConfiguredAvailabilityZones):
|
||||
|
||||
def __init__(self):
|
||||
super(NsxV3AvailabilityZones, self).__init__(
|
||||
cfg.CONF.nsx_v3.availability_zones,
|
||||
NsxV3AvailabilityZone)
|
@ -78,6 +78,7 @@ from sqlalchemy import exc as sql_exc
|
||||
|
||||
from vmware_nsx._i18n import _, _LE, _LI, _LW
|
||||
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
|
||||
@ -93,6 +94,7 @@ from vmware_nsx.extensions import advancedserviceproviders as as_providers
|
||||
from vmware_nsx.extensions import maclearning as mac_ext
|
||||
from vmware_nsx.extensions import providersecuritygroup as provider_sg
|
||||
from vmware_nsx.extensions import securitygrouplogging as sg_logging
|
||||
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.qos.common import utils as qos_com_utils
|
||||
from vmware_nsx.services.qos.nsx_v3 import driver as qos_driver
|
||||
@ -134,7 +136,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
portsecurity_db.PortSecurityDbMixin,
|
||||
extradhcpopt_db.ExtraDhcpOptMixin,
|
||||
dns_db.DNSDbMixin,
|
||||
mac_db.MacLearningDbMixin):
|
||||
mac_db.MacLearningDbMixin,
|
||||
nsx_com_az.NSXAvailabilityZonesPluginCommon):
|
||||
|
||||
__native_bulk_support = True
|
||||
__native_pagination_support = True
|
||||
@ -195,6 +198,11 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
self.cfg_group = 'nsx_v3' # group name for nsx_v3 section in nsx.ini
|
||||
self.tier0_groups_dict = {}
|
||||
|
||||
# Initialize the network availability zones, which will be used only
|
||||
# when native_dhcp_metadata is True
|
||||
self.init_availability_zones()
|
||||
|
||||
# Translate configured transport zones, routers, dhcp profile and
|
||||
# metadata proxy names to uuid.
|
||||
self._translate_configured_names_to_uuids()
|
||||
@ -240,12 +248,24 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
# Each extension driver that supports extend attribute for the resources
|
||||
# can add those attribute to the result.
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.NETWORKS, ['_ext_extend_network_dict'])
|
||||
attributes.NETWORKS, ['_ext_extend_network_dict',
|
||||
'_extend_availability_zone_hints'])
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.PORTS, ['_ext_extend_port_dict'])
|
||||
db_base_plugin_v2.NeutronDbPluginV2.register_dict_extend_funcs(
|
||||
attributes.SUBNETS, ['_ext_extend_subnet_dict'])
|
||||
|
||||
def init_availability_zones(self):
|
||||
# availability zones are supported only with native dhcp
|
||||
# if not - the default az will be loaded and used internally only
|
||||
if (cfg.CONF.nsx_v3.availability_zones and
|
||||
not cfg.CONF.nsx_v3.native_dhcp_metadata):
|
||||
msg = _("Availability zones are not supported without native "
|
||||
"DHCP metadata")
|
||||
LOG.error(msg)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
self._availability_zones_data = nsx_az.NsxV3AvailabilityZones()
|
||||
|
||||
def _init_nsx_profiles(self):
|
||||
LOG.debug("Initializing NSX v3 port spoofguard switching profile")
|
||||
if not self._init_port_security_profile():
|
||||
@ -304,23 +324,17 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
cfg.CONF.nsx_v3.default_tier0_router)
|
||||
self._default_tier0_router = rtr_id
|
||||
|
||||
self._native_dhcp_profile_uuid = None
|
||||
self._native_md_proxy_uuid = None
|
||||
# Validate and translate native dhcp profiles per az
|
||||
if cfg.CONF.nsx_v3.native_dhcp_metadata:
|
||||
if cfg.CONF.nsx_v3.dhcp_profile:
|
||||
id = self.nsxlib.native_dhcp_profile.get_id_by_name_or_id(
|
||||
cfg.CONF.nsx_v3.dhcp_profile)
|
||||
self._native_dhcp_profile_uuid = id
|
||||
else:
|
||||
if not cfg.CONF.nsx_v3.dhcp_profile:
|
||||
raise cfg.RequiredOptError("dhcp_profile")
|
||||
|
||||
if cfg.CONF.nsx_v3.metadata_proxy:
|
||||
proxy_id = self.nsxlib.native_md_proxy.get_id_by_name_or_id(
|
||||
cfg.CONF.nsx_v3.metadata_proxy)
|
||||
self._native_md_proxy_uuid = proxy_id
|
||||
else:
|
||||
if not cfg.CONF.nsx_v3.metadata_proxy:
|
||||
raise cfg.RequiredOptError("metadata_proxy")
|
||||
|
||||
for az in self.get_azs_list():
|
||||
az.translate_configured_names_to_uuids(self.nsxlib)
|
||||
|
||||
def _extend_port_dict_binding(self, context, port_data):
|
||||
port_data[pbin.VIF_TYPE] = pbin.VIF_TYPE_OVS
|
||||
port_data[pbin.VNIC_TYPE] = pbin.VNIC_NORMAL
|
||||
@ -515,25 +529,27 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
|
||||
def _init_native_dhcp(self):
|
||||
try:
|
||||
for az in self.get_azs_list():
|
||||
nsx_resources.DhcpProfile(self._nsx_client).get(
|
||||
self._native_dhcp_profile_uuid)
|
||||
az._native_dhcp_profile_uuid)
|
||||
self._dhcp_server = nsx_resources.LogicalDhcpServer(
|
||||
self._nsx_client)
|
||||
except nsx_lib_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Unable to retrieve DHCP Profile %s, "
|
||||
"native DHCP service is not supported"),
|
||||
self._native_dhcp_profile_uuid)
|
||||
az._native_dhcp_profile_uuid)
|
||||
|
||||
def _init_native_metadata(self):
|
||||
try:
|
||||
for az in self.get_azs_list():
|
||||
nsx_resources.MetaDataProxy(self._nsx_client).get(
|
||||
self._native_md_proxy_uuid)
|
||||
az._native_md_proxy_uuid)
|
||||
except nsx_lib_exc.ManagerError:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.error(_LE("Unable to retrieve Metadata Proxy %s, "
|
||||
"native metadata service is not supported"),
|
||||
self._native_md_proxy_uuid)
|
||||
az._native_md_proxy_uuid)
|
||||
|
||||
def _setup_rpc(self):
|
||||
self.endpoints = [dhcp_rpc.DhcpRpcCallback(),
|
||||
@ -778,6 +794,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
self._create_network_at_the_backend(context, net_data))
|
||||
is_backend_network = True
|
||||
try:
|
||||
az_name = nsx_az.DEFAULT_NAME
|
||||
with context.session.begin(subtransactions=True):
|
||||
# Create network in Neutron
|
||||
created_net = super(NsxV3Plugin, self).create_network(context,
|
||||
@ -791,14 +808,16 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
self._process_l3_create(context, created_net, net_data)
|
||||
|
||||
if az_ext.AZ_HINTS in net_data:
|
||||
net_hints = net_data[az_ext.AZ_HINTS]
|
||||
self.validate_availability_zones(context, 'network',
|
||||
net_data[az_ext.AZ_HINTS])
|
||||
az_hints = az_ext.convert_az_list_to_string(
|
||||
net_data[az_ext.AZ_HINTS])
|
||||
net_id = created_net['id']
|
||||
super(NsxV3Plugin, self).update_network(context,
|
||||
net_id, {'network': {az_ext.AZ_HINTS: az_hints}})
|
||||
created_net[az_ext.AZ_HINTS] = az_hints
|
||||
net_hints)
|
||||
if net_hints:
|
||||
az_name = net_hints[0]
|
||||
az_hints = az_ext.convert_az_list_to_string(net_hints)
|
||||
super(NsxV3Plugin, self).update_network(
|
||||
context,
|
||||
created_net['id'],
|
||||
{'network': {az_ext.AZ_HINTS: az_hints}})
|
||||
|
||||
if is_provider_net:
|
||||
# Save provider network fields, needed by get_network()
|
||||
@ -817,6 +836,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
nsx_net_id)
|
||||
|
||||
if is_backend_network and cfg.CONF.nsx_v3.native_dhcp_metadata:
|
||||
az = self.get_az_by_hint(az_name)
|
||||
# Enable native metadata proxy for this network.
|
||||
tags = self.nsxlib.build_v3_tags_payload(
|
||||
net_data, resource_type='os-neutron-net-id',
|
||||
@ -825,7 +845,7 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
'mdproxy', created_net['name'] or 'network'),
|
||||
created_net['id'])
|
||||
md_port = self._port_client.create(
|
||||
nsx_net_id, self._native_md_proxy_uuid,
|
||||
nsx_net_id, az._native_md_proxy_uuid,
|
||||
tags=tags, name=name,
|
||||
attachment_type=nsxlib_consts.ATTACHMENT_MDPROXY)
|
||||
LOG.debug("Created MD-Proxy logical port %(port)s "
|
||||
@ -1018,10 +1038,11 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
existing_ports = super(NsxV3Plugin, self).get_ports(
|
||||
context, filters={'network_id': [network['id']],
|
||||
'fixed_ips': {'subnet_id': [subnet['id']]}})
|
||||
az = self.get_network_az(network)
|
||||
port_data = {
|
||||
"name": "",
|
||||
"admin_state_up": True,
|
||||
"device_id": self._native_dhcp_profile_uuid,
|
||||
"device_id": az._native_dhcp_profile_uuid,
|
||||
"device_owner": const.DEVICE_OWNER_DHCP,
|
||||
"network_id": network['id'],
|
||||
"tenant_id": network["tenant_id"],
|
||||
@ -1034,8 +1055,10 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
network, resource_type='os-neutron-net-id',
|
||||
project_name=context.tenant_name)
|
||||
server_data = self.nsxlib.native_dhcp.build_server_config(
|
||||
network, subnet, neutron_port, net_tags)
|
||||
server_data['dhcp_profile_id'] = self._native_dhcp_profile_uuid
|
||||
network, subnet, neutron_port, net_tags,
|
||||
default_dns_nameservers=az.nameservers,
|
||||
default_dns_domain=az.dns_domain)
|
||||
server_data['dhcp_profile_id'] = az._native_dhcp_profile_uuid
|
||||
nsx_net_id = self._get_network_nsx_id(context, network['id'])
|
||||
port_tags = self.nsxlib.build_v3_tags_payload(
|
||||
neutron_port, resource_type='os-neutron-dport-id',
|
||||
@ -1383,7 +1406,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
port = self._get_port(context, binding['port_id'])
|
||||
self._update_dhcp_binding_on_server(
|
||||
context, binding, port['mac_address'],
|
||||
binding['ip_address'], kwargs['gateway_ip'])
|
||||
binding['ip_address'], kwargs['gateway_ip'],
|
||||
port['network_id'])
|
||||
|
||||
if (cfg.CONF.nsx_v3.metadata_on_demand and
|
||||
not cfg.CONF.nsx_v3.native_dhcp_metadata):
|
||||
@ -1762,10 +1786,11 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
msg = (_("DHCP option %s is not supported") % opt_name)
|
||||
raise n_exc.InvalidInput(error_message=msg)
|
||||
|
||||
def _get_dhcp_options(self, ip, extra_dhcp_opts):
|
||||
def _get_dhcp_options(self, context, ip, extra_dhcp_opts, net_id):
|
||||
# Always add option121.
|
||||
net_az = self.get_network_az_by_net_id(context, net_id)
|
||||
options = {'option121': {'static_routes': [
|
||||
{'network': '%s' % cfg.CONF.nsx_v3.native_metadata_route,
|
||||
{'network': '%s' % net_az.native_metadata_route,
|
||||
'next_hop': ip}]}}
|
||||
# Adding extra options only if configured on port
|
||||
if extra_dhcp_opts:
|
||||
@ -1797,7 +1822,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
gateway_ip = self.get_subnet(
|
||||
context, subnet_id).get('gateway_ip')
|
||||
options = self._get_dhcp_options(
|
||||
ip, port.get(ext_edo.EXTRADHCPOPTS))
|
||||
context, ip, port.get(ext_edo.EXTRADHCPOPTS),
|
||||
port['network_id'])
|
||||
binding = self._dhcp_server.create_binding(
|
||||
dhcp_service_id, port['mac_address'], ip, hostname,
|
||||
cfg.CONF.nsx_v3.dhcp_lease_time, options, gateway_ip)
|
||||
@ -1933,7 +1959,8 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
if binding:
|
||||
self._update_dhcp_binding_on_server(
|
||||
context, binding, new_port['mac_address'],
|
||||
ips_to_add[i][1], dhcp_opts=dhcp_opts)
|
||||
ips_to_add[i][1], old_port['network_id'],
|
||||
dhcp_opts=dhcp_opts)
|
||||
else:
|
||||
for (subnet_id, ip) in ips_to_delete:
|
||||
binding = self._find_dhcp_binding(subnet_id, ip,
|
||||
@ -1957,18 +1984,21 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
for binding in bindings:
|
||||
self._update_dhcp_binding_on_server(
|
||||
context, binding, new_port['mac_address'],
|
||||
binding['ip_address'],
|
||||
binding['ip_address'], old_port['network_id'],
|
||||
dhcp_opts=dhcp_opts if dhcp_opts_changed else None)
|
||||
|
||||
def _update_dhcp_binding_on_server(self, context, binding, mac, ip,
|
||||
gateway_ip=False, dhcp_opts=None):
|
||||
net_id, gateway_ip=False,
|
||||
dhcp_opts=None):
|
||||
try:
|
||||
data = {'mac_address': mac, 'ip_address': ip}
|
||||
if ip != binding['ip_address']:
|
||||
data['host_name'] = 'host-%s' % ip.replace('.', '-')
|
||||
data['options'] = self._get_dhcp_options(ip, dhcp_opts)
|
||||
data['options'] = self._get_dhcp_options(
|
||||
context, ip, dhcp_opts, net_id)
|
||||
elif dhcp_opts is not None:
|
||||
data['options'] = self._get_dhcp_options(ip, dhcp_opts)
|
||||
data['options'] = self._get_dhcp_options(
|
||||
context, ip, dhcp_opts, net_id)
|
||||
if gateway_ip is not False:
|
||||
# Note that None is valid for gateway_ip, means deleting it.
|
||||
data['gateway_ip'] = gateway_ip
|
||||
@ -3479,3 +3509,46 @@ class NsxV3Plugin(agentschedulers_db.AZDhcpAgentSchedulerDbMixin,
|
||||
def save_security_group_rule_mappings(self, context, firewall_rules):
|
||||
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)
|
||||
|
||||
#TODO(asarfaty): We may need to use the filters arg, but now it
|
||||
# is here only for overriding the original api
|
||||
result = {}
|
||||
for az in self._availability_zones_data.list_availability_zones():
|
||||
# Add this availability zone as a network resource
|
||||
result[(az, 'network')] = True
|
||||
return result
|
||||
|
||||
def validate_availability_zones(self, context, resource_type,
|
||||
availability_zones):
|
||||
# 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 _extend_availability_zone_hints(self, net_res, net_db):
|
||||
net_res[az_ext.AZ_HINTS] = az_ext.convert_az_string_to_list(
|
||||
net_db[az_ext.AZ_HINTS])
|
||||
if cfg.CONF.nsx_v3.native_dhcp_metadata:
|
||||
# When using the configured AZs, the az will always be the same
|
||||
# as the hint (or default if none)
|
||||
if net_res[az_ext.AZ_HINTS]:
|
||||
az_name = net_res[az_ext.AZ_HINTS][0]
|
||||
else:
|
||||
az_name = nsx_az.DEFAULT_NAME
|
||||
net_res[az_ext.AVAILABILITY_ZONES] = [az_name]
|
||||
|
||||
def get_network_az_by_net_id(self, context, network_id):
|
||||
try:
|
||||
network = self.get_network(context, network_id)
|
||||
except Exception:
|
||||
return self.get_default_az()
|
||||
|
||||
return self.get_network_az(network)
|
||||
|
@ -144,6 +144,5 @@ def get_nsxlib_wrapper(nsx_username=None, nsx_password=None, basic_auth=False):
|
||||
plugin_tag=NSX_NEUTRON_PLUGIN,
|
||||
plugin_ver=n_version.version_info.release_string(),
|
||||
dns_nameservers=cfg.CONF.nsx_v3.nameservers,
|
||||
dns_domain=cfg.CONF.nsx_v3.dns_domain,
|
||||
dhcp_profile_uuid=cfg.CONF.nsx_v3.dhcp_profile)
|
||||
dns_domain=cfg.CONF.nsx_v3.dns_domain)
|
||||
return v3.NsxLib(nsxlib_config)
|
||||
|
@ -55,6 +55,7 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
|
||||
return
|
||||
|
||||
dhcp_profile_uuid = None
|
||||
# TODO(asarfaty) Add availability zones support here
|
||||
if kwargs.get('property'):
|
||||
properties = admin_utils.parse_multi_keyval_opt(kwargs['property'])
|
||||
dhcp_profile_uuid = properties.get('dhcp_profile_uuid')
|
||||
@ -91,6 +92,8 @@ def nsx_update_dhcp_bindings(resource, event, trigger, **kwargs):
|
||||
net_tags = nsxlib.build_v3_tags_payload(
|
||||
network, resource_type='os-neutron-net-id',
|
||||
project_name='admin')
|
||||
# TODO(asarfaty): add default_dns_nameservers & dns_domain
|
||||
# from availability zone
|
||||
server_data = nsxlib.native_dhcp.build_server_config(
|
||||
network, subnet, port, net_tags)
|
||||
server_data['dhcp_profile_id'] = dhcp_profile_uuid
|
||||
|
112
vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py
Normal file
112
vmware_nsx/tests/unit/nsx_v3/test_availability_zones.py
Normal file
@ -0,0 +1,112 @@
|
||||
# Copyright 2017 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_v3 import availability_zones as nsx_az
|
||||
|
||||
|
||||
class Nsxv3AvailabilityZonesTestCase(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(Nsxv3AvailabilityZonesTestCase, 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_v3")
|
||||
self.global_dhcp_profile = uuidutils.generate_uuid()
|
||||
cfg.CONF.set_override(
|
||||
"dhcp_profile", self.global_dhcp_profile, group="nsx_v3")
|
||||
cfg.CONF.set_override(
|
||||
"native_metadata_route", "1.1.1.1", group="nsx_v3")
|
||||
cfg.CONF.set_override("dns_domain", "xxx.com", group="nsx_v3")
|
||||
cfg.CONF.set_override("nameservers", ["10.1.1.1"], group="nsx_v3")
|
||||
|
||||
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"]):
|
||||
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)
|
||||
|
||||
def test_simple_availability_zone(self):
|
||||
self._config_az()
|
||||
az = nsx_az.NsxV3AvailabilityZone(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)
|
||||
|
||||
def test_missing_group_section(self):
|
||||
self.assertRaises(
|
||||
nsx_exc.NsxInvalidConfiguration,
|
||||
nsx_az.NsxV3AvailabilityZone,
|
||||
"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.NsxV3AvailabilityZone,
|
||||
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.NsxV3AvailabilityZone,
|
||||
self.az_name)
|
||||
|
||||
def test_availability_zone_missing_md_route(self):
|
||||
self._config_az(native_metadata_route=None)
|
||||
az = nsx_az.NsxV3AvailabilityZone(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.NsxV3AvailabilityZone(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.NsxV3AvailabilityZone(self.az_name)
|
||||
self.assertEqual(["10.1.1.1"], az.nameservers)
|
@ -16,15 +16,17 @@
|
||||
import mock
|
||||
import netaddr
|
||||
|
||||
from neutron.extensions import securitygroup as secgrp
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
|
||||
from neutron.extensions import securitygroup as secgrp
|
||||
from neutron_lib.api.definitions import provider_net as pnet
|
||||
from neutron_lib import constants
|
||||
from neutron_lib import context
|
||||
from neutron_lib import exceptions as n_exc
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import uuidutils
|
||||
from neutron_lib.plugins import directory
|
||||
|
||||
from vmware_nsx.common import config
|
||||
from vmware_nsx.common import exceptions as nsx_exc
|
||||
from vmware_nsx.common import utils
|
||||
from vmware_nsx.db import db as nsx_db
|
||||
@ -34,6 +36,26 @@ from vmware_nsxlib.v3 import nsx_constants
|
||||
from vmware_nsxlib.v3 import resources as nsx_resources
|
||||
|
||||
|
||||
def set_az_in_config(name, metadata_proxy="metadata_proxy1",
|
||||
dhcp_profile="dhcp_profile1",
|
||||
native_metadata_route="2.2.2.2",
|
||||
dns_domain='aaaa',
|
||||
nameservers=['bbbb']):
|
||||
group_name = 'az:%s' % name
|
||||
cfg.CONF.set_override('availability_zones', [name], group="nsx_v3")
|
||||
config.register_nsxv3_azs(cfg.CONF, [name])
|
||||
cfg.CONF.set_override("metadata_proxy", metadata_proxy,
|
||||
group=group_name)
|
||||
cfg.CONF.set_override("dhcp_profile", dhcp_profile,
|
||||
group=group_name)
|
||||
cfg.CONF.set_override("native_metadata_route", native_metadata_route,
|
||||
group=group_name)
|
||||
cfg.CONF.set_override("dns_domain", dns_domain,
|
||||
group=group_name)
|
||||
cfg.CONF.set_override("nameservers", nameservers,
|
||||
group=group_name)
|
||||
|
||||
|
||||
class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin):
|
||||
|
||||
def setUp(self):
|
||||
@ -42,11 +64,15 @@ class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin):
|
||||
self._orig_native_dhcp_metadata = cfg.CONF.nsx_v3.native_dhcp_metadata
|
||||
cfg.CONF.set_override('dhcp_agent_notification', False)
|
||||
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
|
||||
self._az_name = 'zone1'
|
||||
self.az_metadata_route = '3.3.3.3'
|
||||
set_az_in_config(self._az_name,
|
||||
native_metadata_route=self.az_metadata_route)
|
||||
self._patcher = mock.patch.object(nsx_resources.DhcpProfile, 'get')
|
||||
self._patcher.start()
|
||||
# Need to run _translate_configured_names_to_uuids and
|
||||
# _init_dhcp_metadata() manually because plugin was started
|
||||
# before setUp() overrides CONF.nsx_v3.native_dhcp_metadata.
|
||||
# Need to run some plugin init methods manually because plugin was
|
||||
# started before setUp() overrides CONF.nsx_v3.native_dhcp_metadata.
|
||||
self.plugin.init_availability_zones()
|
||||
self.plugin._translate_configured_names_to_uuids()
|
||||
self.plugin._init_dhcp_metadata()
|
||||
|
||||
@ -741,6 +767,96 @@ class NsxNativeDhcpTestCase(test_plugin.NsxV3PluginTestCaseMixin):
|
||||
port['port']['id'])
|
||||
self.assertEqual(delete_dhcp_binding.call_count, 2)
|
||||
|
||||
def test_create_network_with_bad_az_hint(self):
|
||||
p = directory.get_plugin()
|
||||
ctx = context.get_admin_context()
|
||||
data = {'network': {
|
||||
'name': 'test-az',
|
||||
'tenant_id': self._tenant_id,
|
||||
'port_security_enabled': False,
|
||||
'admin_state_up': True,
|
||||
'shared': False,
|
||||
'availability_zone_hints': ['bad_hint']
|
||||
}}
|
||||
self.assertRaises(n_exc.NeutronException,
|
||||
p.create_network,
|
||||
ctx, data)
|
||||
|
||||
def test_create_network_with_az_hint(self):
|
||||
p = directory.get_plugin()
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
data = {'network': {
|
||||
'name': 'test-az',
|
||||
'tenant_id': self._tenant_id,
|
||||
'port_security_enabled': False,
|
||||
'admin_state_up': True,
|
||||
'shared': False,
|
||||
'availability_zone_hints': [self._az_name]
|
||||
}}
|
||||
|
||||
# network creation should succeed
|
||||
net = p.create_network(ctx, data)
|
||||
self.assertEqual([self._az_name],
|
||||
net['availability_zone_hints'])
|
||||
self.assertEqual([self._az_name],
|
||||
net['availability_zones'])
|
||||
|
||||
def test_create_network_with_no_az_hint(self):
|
||||
p = directory.get_plugin()
|
||||
ctx = context.get_admin_context()
|
||||
|
||||
data = {'network': {
|
||||
'name': 'test-az',
|
||||
'tenant_id': self._tenant_id,
|
||||
'port_security_enabled': False,
|
||||
'admin_state_up': True,
|
||||
'shared': False
|
||||
}}
|
||||
|
||||
# network creation should succeed
|
||||
net = p.create_network(ctx, data)
|
||||
self.assertEqual([],
|
||||
net['availability_zone_hints'])
|
||||
self.assertEqual(['default'],
|
||||
net['availability_zones'])
|
||||
|
||||
def test_dhcp_service_with_create_az_network(self):
|
||||
# Test if DHCP service is disabled on a network when it is created.
|
||||
with self.network(availability_zone_hints=[self._az_name],
|
||||
arg_list=('availability_zone_hints',)) as network:
|
||||
self._verify_dhcp_service(network['network']['id'],
|
||||
network['network']['tenant_id'], False)
|
||||
|
||||
def test_dhcp_binding_with_create_az_port(self):
|
||||
# Test if DHCP binding is added when a compute port is created.
|
||||
with mock.patch.object(nsx_resources.LogicalDhcpServer,
|
||||
'create_binding',
|
||||
return_value={"id": uuidutils.generate_uuid()}
|
||||
) as create_dhcp_binding:
|
||||
with self.network(
|
||||
availability_zone_hints=[self._az_name],
|
||||
arg_list=('availability_zone_hints',)) as network:
|
||||
with self.subnet(enable_dhcp=True, network=network) as subnet:
|
||||
device_owner = constants.DEVICE_OWNER_COMPUTE_PREFIX + 'X'
|
||||
device_id = uuidutils.generate_uuid()
|
||||
with self.port(subnet=subnet, device_owner=device_owner,
|
||||
device_id=device_id) as port:
|
||||
dhcp_service = nsx_db.get_nsx_service_binding(
|
||||
context.get_admin_context().session,
|
||||
subnet['subnet']['network_id'],
|
||||
nsx_constants.SERVICE_DHCP)
|
||||
ip = port['port']['fixed_ips'][0]['ip_address']
|
||||
hostname = 'host-%s' % ip.replace('.', '-')
|
||||
options = {'option121': {'static_routes': [
|
||||
{'network': '%s' % self.az_metadata_route,
|
||||
'next_hop': ip}]}}
|
||||
create_dhcp_binding.assert_called_once_with(
|
||||
dhcp_service['nsx_service_id'],
|
||||
port['port']['mac_address'], ip, hostname,
|
||||
cfg.CONF.nsx_v3.dhcp_lease_time, options,
|
||||
subnet['subnet']['gateway_ip'])
|
||||
|
||||
|
||||
class NsxNativeMetadataTestCase(test_plugin.NsxV3PluginTestCaseMixin):
|
||||
|
||||
@ -750,11 +866,12 @@ class NsxNativeMetadataTestCase(test_plugin.NsxV3PluginTestCaseMixin):
|
||||
self._orig_native_dhcp_metadata = cfg.CONF.nsx_v3.native_dhcp_metadata
|
||||
cfg.CONF.set_override('dhcp_agent_notification', False)
|
||||
cfg.CONF.set_override('native_dhcp_metadata', True, 'nsx_v3')
|
||||
self._az_name = 'zone1'
|
||||
self._az_metadata_proxy = 'dummy'
|
||||
set_az_in_config(self._az_name, metadata_proxy=self._az_metadata_proxy)
|
||||
self._patcher = mock.patch.object(nsx_resources.MetaDataProxy, 'get')
|
||||
self._patcher.start()
|
||||
# Need to run _translate_configured_names_to_uuids and
|
||||
# _init_dhcp_metadata() manually because plugin was started
|
||||
# before setUp() overrides CONF.nsx_v3.native_dhcp_metadata.
|
||||
self.plugin.init_availability_zones()
|
||||
self.plugin._translate_configured_names_to_uuids()
|
||||
self.plugin._init_dhcp_metadata()
|
||||
|
||||
@ -801,6 +918,27 @@ class NsxNativeMetadataTestCase(test_plugin.NsxV3PluginTestCaseMixin):
|
||||
tags=tags, name=name,
|
||||
attachment_type=nsx_constants.ATTACHMENT_MDPROXY)
|
||||
|
||||
def test_metadata_proxy_with_create_az_network(self):
|
||||
# Test if native metadata proxy is enabled on a network when it is
|
||||
# created.
|
||||
with mock.patch.object(nsx_resources.LogicalPort,
|
||||
'create') as create_logical_port:
|
||||
with self.network(
|
||||
availability_zone_hints=[self._az_name],
|
||||
arg_list=('availability_zone_hints',)) as network:
|
||||
nsx_net_id = self.plugin._get_network_nsx_id(
|
||||
context.get_admin_context(), network['network']['id'])
|
||||
tags = self.plugin.nsxlib.build_v3_tags_payload(
|
||||
network['network'], resource_type='os-neutron-net-id',
|
||||
project_name=None)
|
||||
name = utils.get_name_and_uuid('%s-%s' % (
|
||||
'mdproxy', network['network']['name'] or 'network'),
|
||||
network['network']['id'])
|
||||
create_logical_port.assert_called_once_with(
|
||||
nsx_net_id, self._az_metadata_proxy,
|
||||
tags=tags, name=name,
|
||||
attachment_type=nsx_constants.ATTACHMENT_MDPROXY)
|
||||
|
||||
def test_metadata_proxy_with_get_subnets(self):
|
||||
# Test if get_subnets() handles advanced-service-provider extension,
|
||||
# which is used when processing metadata requests.
|
||||
|
@ -81,6 +81,9 @@ def _mock_nsx_backend_calls():
|
||||
def _return_id(*args, **kwargs):
|
||||
return uuidutils.generate_uuid()
|
||||
|
||||
def _return_same(key, *args, **kwargs):
|
||||
return key
|
||||
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.resources.SwitchingProfile.find_by_display_name",
|
||||
return_value=[fake_profile]
|
||||
@ -120,7 +123,7 @@ def _mock_nsx_backend_calls():
|
||||
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.NsxLibMetadataProxy.get_id_by_name_or_id",
|
||||
return_value=NSX_METADATA_PROXY_ID).start()
|
||||
side_effect=_return_same).start()
|
||||
|
||||
mock.patch(
|
||||
"vmware_nsxlib.v3.resources.LogicalPort.create",
|
||||
|
Loading…
Reference in New Issue
Block a user