NSXv: Add metadata configuration to the availability zones
The next global configurations are now added also per AZ: - mgt_net_moid - mgt_net_proxy_ips - mgt_net_proxy_netmask - mgt_net_default_gateway - external_network - vdn_scope_id - dvs_id In case any of them is not defined in the AZ section, the global value will be used. Change-Id: I5fca433fb86163cee84e3b9fc54182017a5f266b
This commit is contained in:
parent
e8889cf17f
commit
2808ededb7
@ -686,6 +686,27 @@ nsxv_az_opts = [
|
||||
help=_("(Optional) Defines edge pool's management range for "
|
||||
"the availability zone. If not defined, the global one "
|
||||
"will be used")),
|
||||
cfg.StrOpt('mgt_net_moid',
|
||||
help=_('(Optional) Portgroup MoRef ID for metadata proxy '
|
||||
'management network')),
|
||||
cfg.ListOpt('mgt_net_proxy_ips',
|
||||
default=[],
|
||||
help=_('(Optional) Comma separated list of management network '
|
||||
'IP addresses for metadata proxy.')),
|
||||
cfg.StrOpt('mgt_net_proxy_netmask',
|
||||
help=_("(Optional) Management network netmask for metadata "
|
||||
"proxy.")),
|
||||
cfg.StrOpt('mgt_net_default_gateway',
|
||||
help=_("(Optional) Management network default gateway for "
|
||||
"metadata proxy.")),
|
||||
cfg.StrOpt('external_network',
|
||||
help=_('(Optional) Network ID for physical network '
|
||||
'connectivity')),
|
||||
cfg.StrOpt('vdn_scope_id',
|
||||
help=_('(Optional) Network scope ID for VXLAN virtual wires')),
|
||||
cfg.StrOpt('dvs_id',
|
||||
help=_('(Optional) DVS MoRef ID for DVS connected to '
|
||||
'Management / Edge cluster')),
|
||||
]
|
||||
|
||||
# Register the configuration options
|
||||
|
@ -1 +1 @@
|
||||
5c8f451290b7
|
||||
14a89ddf96e2
|
@ -0,0 +1,43 @@
|
||||
# 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 Adds a 'availability_zone' attribute to internal-networks table
|
||||
|
||||
Revision ID: 14a89ddf96e2
|
||||
Revises: 5c8f451290b7
|
||||
Create Date: 2017-02-05 14:34:21.163418
|
||||
|
||||
"""
|
||||
|
||||
# revision identifiers, used by Alembic.
|
||||
revision = '14a89ddf96e2'
|
||||
down_revision = '5c8f451290b7'
|
||||
|
||||
from alembic import op
|
||||
import sqlalchemy as sa
|
||||
from sqlalchemy.engine import reflection
|
||||
|
||||
|
||||
def upgrade():
|
||||
table_name = 'nsxv_internal_networks'
|
||||
# Add the new column
|
||||
op.add_column(table_name, sa.Column(
|
||||
'availability_zone', sa.String(36), server_default='default'))
|
||||
# replace the old primary key constraint with a new one for both
|
||||
# purpose & az
|
||||
inspector = reflection.Inspector.from_engine(op.get_bind())
|
||||
pk_constraint = inspector.get_pk_constraint(table_name)
|
||||
op.drop_constraint(pk_constraint.get('name'), table_name, type_='primary')
|
||||
op.create_primary_key(None, table_name,
|
||||
['network_purpose', 'availability_zone'])
|
@ -131,6 +131,12 @@ def get_edge_availability_zone(session, edge_id):
|
||||
return binding['availability_zone']
|
||||
|
||||
|
||||
def get_router_availability_zone(session, router_id):
|
||||
binding = get_nsxv_router_binding(session, router_id)
|
||||
if binding:
|
||||
return binding['availability_zone']
|
||||
|
||||
|
||||
def clean_edge_router_binding(session, edge_id):
|
||||
with session.begin(subtransactions=True):
|
||||
(session.query(nsxv_models.NsxvRouterBinding).
|
||||
@ -220,14 +226,16 @@ def allocate_edge_vnic(session, edge_id, network_id):
|
||||
raise nsx_exc.NsxPluginException(err_msg=msg)
|
||||
|
||||
|
||||
def allocate_edge_vnic_with_tunnel_index(session, edge_id, network_id):
|
||||
def allocate_edge_vnic_with_tunnel_index(session, edge_id, network_id,
|
||||
availability_zone):
|
||||
"""Allocate an available edge vnic with tunnel index to network."""
|
||||
|
||||
# TODO(berlin): temporary solution to let metadata and dhcp use
|
||||
# different vnics
|
||||
net_list = get_nsxv_internal_network(
|
||||
session, constants.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
metadata_net_id = net_list[0]['network_id'] if net_list else None
|
||||
int_net = get_nsxv_internal_network(
|
||||
session, constants.InternalEdgePurposes.INTER_EDGE_PURPOSE,
|
||||
availability_zone)
|
||||
metadata_net_id = int_net['network_id'] if int_net else None
|
||||
|
||||
with session.begin(subtransactions=True):
|
||||
query = session.query(nsxv_models.NsxvEdgeVnicBinding)
|
||||
@ -353,36 +361,44 @@ def clean_edge_dhcp_static_bindings_by_edge(session, edge_id):
|
||||
edge_id=edge_id).delete()
|
||||
|
||||
|
||||
def create_nsxv_internal_network(session, network_purpose, network_id):
|
||||
def create_nsxv_internal_network(session, network_purpose,
|
||||
availability_zone, network_id):
|
||||
with session.begin(subtransactions=True):
|
||||
try:
|
||||
network = nsxv_models.NsxvInternalNetworks(
|
||||
network_purpose=network_purpose,
|
||||
network_id=network_id)
|
||||
network_id=network_id,
|
||||
availability_zone=availability_zone)
|
||||
session.add(network)
|
||||
except db_exc.DBDuplicateEntry:
|
||||
with excutils.save_and_reraise_exception():
|
||||
LOG.exception(_LE("Duplicate internal network for purpose %s"),
|
||||
network_purpose)
|
||||
LOG.exception(_LE("Duplicate internal network for purpose "
|
||||
"%(p)s and availabiltiy zone %(az)s"),
|
||||
{'p': network_purpose,
|
||||
'az': availability_zone})
|
||||
|
||||
|
||||
def get_nsxv_internal_network(session, network_purpose):
|
||||
def get_nsxv_internal_network(session, network_purpose, availability_zone):
|
||||
with session.begin(subtransactions=True):
|
||||
net_list = (session.query(nsxv_models.NsxvInternalNetworks).
|
||||
filter_by(network_purpose=network_purpose,
|
||||
availability_zone=availability_zone).all())
|
||||
if net_list:
|
||||
# Should have only one results as purpose+az are the keys
|
||||
return net_list[0]
|
||||
|
||||
|
||||
def get_nsxv_internal_networks(session, network_purpose):
|
||||
with session.begin(subtransactions=True):
|
||||
return (session.query(nsxv_models.NsxvInternalNetworks).
|
||||
filter_by(network_purpose=network_purpose).all())
|
||||
|
||||
|
||||
def update_nsxv_internal_network(session, network_purpose, network_id):
|
||||
with session.begin(subtransactions=True):
|
||||
nets = get_nsxv_internal_network(session, network_purpose)
|
||||
for net in nets:
|
||||
net['network_id'] = network_id
|
||||
|
||||
|
||||
def delete_nsxv_internal_network(session, network_purpose):
|
||||
def delete_nsxv_internal_network(session, network_purpose, network_id):
|
||||
with session.begin(subtransactions=True):
|
||||
return (session.query(nsxv_models.NsxvInternalNetworks).
|
||||
filter_by(network_purpose=network_purpose).delete())
|
||||
filter_by(network_purpose=network_purpose,
|
||||
network_id=network_id).delete())
|
||||
|
||||
|
||||
def create_nsxv_internal_edge(session, ext_ip_address, purpose, router_id):
|
||||
|
@ -79,7 +79,6 @@ class NsxvEdgeDhcpStaticBinding(model_base.BASEV2, models.TimestampMixin):
|
||||
|
||||
class NsxvInternalNetworks(model_base.BASEV2, models.TimestampMixin):
|
||||
"""Represents internal networks between NSXV plugin elements."""
|
||||
|
||||
__tablename__ = 'nsxv_internal_networks'
|
||||
|
||||
network_purpose = sa.Column(
|
||||
@ -89,11 +88,12 @@ class NsxvInternalNetworks(model_base.BASEV2, models.TimestampMixin):
|
||||
network_id = sa.Column(sa.String(36),
|
||||
sa.ForeignKey("networks.id", ondelete="CASCADE"),
|
||||
nullable=True)
|
||||
availability_zone = sa.Column(sa.String(36),
|
||||
primary_key=True)
|
||||
|
||||
|
||||
class NsxvInternalEdges(model_base.BASEV2, models.TimestampMixin):
|
||||
"""Represents internal Edge appliances for NSXV plugin operations."""
|
||||
|
||||
__tablename__ = 'nsxv_internal_edges'
|
||||
|
||||
ext_ip_address = sa.Column(sa.String(64), primary_key=True)
|
||||
|
@ -71,6 +71,17 @@ class ConfiguredAvailabilityZone(object):
|
||||
# using the global ones instead.
|
||||
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
|
||||
self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool
|
||||
self.external_network = cfg.CONF.nsxv.external_network
|
||||
self.vdn_scope_id = cfg.CONF.nsxv.vdn_scope_id
|
||||
self.dvs_id = cfg.CONF.nsxv.dvs_id
|
||||
|
||||
# No support for metadata per az
|
||||
self.az_metadata_support = False
|
||||
self.mgt_net_moid = None
|
||||
self.mgt_net_proxy_ips = []
|
||||
self.mgt_net_proxy_netmask = None
|
||||
self.mgt_net_default_gateway = None
|
||||
|
||||
elif config_line:
|
||||
# Newer configuration - the name of the availability zone can be
|
||||
# used to get the rest of the configuration for this AZ
|
||||
@ -113,6 +124,57 @@ class ConfiguredAvailabilityZone(object):
|
||||
if not self.backup_edge_pool:
|
||||
self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool
|
||||
|
||||
self.external_network = az_info.get('external_network')
|
||||
if not self.external_network:
|
||||
self.external_network = cfg.CONF.nsxv.external_network
|
||||
|
||||
self.vdn_scope_id = az_info.get('vdn_scope_id')
|
||||
if not self.vdn_scope_id:
|
||||
self.vdn_scope_id = cfg.CONF.nsxv.vdn_scope_id
|
||||
|
||||
self.dvs_id = az_info.get('dvs_id')
|
||||
if not self.dvs_id:
|
||||
self.dvs_id = cfg.CONF.nsxv.dvs_id
|
||||
|
||||
# Support for metadata per az only if configured, and different
|
||||
# from the global one
|
||||
self.mgt_net_proxy_ips = az_info.get('mgt_net_proxy_ips')
|
||||
if self.mgt_net_proxy_ips:
|
||||
# make sure there are no over lapping ips with the
|
||||
# global configuration
|
||||
if (set(self.mgt_net_proxy_ips) &
|
||||
set(cfg.CONF.nsxv.mgt_net_proxy_ips)):
|
||||
raise nsx_exc.NsxInvalidConfiguration(
|
||||
opt_name="mgt_net_proxy_ips",
|
||||
opt_value='None',
|
||||
reason=(_("mgt_net_proxy_ips for availability zone "
|
||||
"%s must be different from global one") %
|
||||
self.name))
|
||||
|
||||
self.az_metadata_support = True
|
||||
self.mgt_net_moid = az_info.get('mgt_net_moid')
|
||||
if not self.mgt_net_moid:
|
||||
self.mgt_net_moid = cfg.CONF.nsxv.mgt_net_moid
|
||||
|
||||
self.mgt_net_proxy_netmask = az_info.get(
|
||||
'mgt_net_proxy_netmask')
|
||||
if not self.mgt_net_proxy_netmask:
|
||||
self.mgt_net_proxy_netmask = (
|
||||
cfg.CONF.nsxv.mgt_net_proxy_netmask)
|
||||
|
||||
self.mgt_net_default_gateway = az_info.get(
|
||||
'mgt_net_default_gateway')
|
||||
if not self.mgt_net_default_gateway:
|
||||
self.mgt_net_default_gateway = (
|
||||
cfg.CONF.nsxv.mgt_net_default_gateway)
|
||||
|
||||
else:
|
||||
self.az_metadata_support = False
|
||||
self.mgt_net_moid = None
|
||||
self.mgt_net_proxy_ips = []
|
||||
self.mgt_net_proxy_netmask = None
|
||||
self.mgt_net_default_gateway = None
|
||||
|
||||
else:
|
||||
# use the default configuration
|
||||
self.name = DEFAULT_NAME
|
||||
@ -122,6 +184,23 @@ class ConfiguredAvailabilityZone(object):
|
||||
self.ha_datastore_id = cfg.CONF.nsxv.ha_datastore_id
|
||||
self.ha_placement_random = cfg.CONF.nsxv.ha_placement_random
|
||||
self.backup_edge_pool = cfg.CONF.nsxv.backup_edge_pool
|
||||
self.az_metadata_support = True
|
||||
self.mgt_net_moid = cfg.CONF.nsxv.mgt_net_moid
|
||||
self.mgt_net_proxy_ips = cfg.CONF.nsxv.mgt_net_proxy_ips
|
||||
self.mgt_net_proxy_netmask = cfg.CONF.nsxv.mgt_net_proxy_netmask
|
||||
self.mgt_net_default_gateway = (
|
||||
cfg.CONF.nsxv.mgt_net_default_gateway)
|
||||
self.external_network = cfg.CONF.nsxv.external_network
|
||||
self.vdn_scope_id = cfg.CONF.nsxv.vdn_scope_id
|
||||
self.dvs_id = cfg.CONF.nsxv.dvs_id
|
||||
|
||||
def is_default(self):
|
||||
return self.name == DEFAULT_NAME
|
||||
|
||||
def supports_metadata(self):
|
||||
# Return True if this az has it's own metadata configuration
|
||||
# If False - it uses the global metadata (if defined)
|
||||
return self.az_metadata_support
|
||||
|
||||
|
||||
class ConfiguredAvailabilityZones(object):
|
||||
@ -147,6 +226,14 @@ class ConfiguredAvailabilityZones(object):
|
||||
resources.append(az.datastore_id)
|
||||
if az.ha_datastore_id:
|
||||
resources.append(az.ha_datastore_id)
|
||||
if az.mgt_net_moid:
|
||||
resources.append(az.mgt_net_moid)
|
||||
if az.external_network:
|
||||
resources.append(az.external_network)
|
||||
if az.vdn_scope_id:
|
||||
resources.append(az.vdn_scope_id)
|
||||
if az.mgt_net_moid:
|
||||
resources.append(az.mgt_net_moid)
|
||||
return resources
|
||||
|
||||
def get_availability_zone(self, name):
|
||||
|
@ -197,7 +197,7 @@ class RouterDistributedDriver(router_driver.RouterBaseDriver):
|
||||
|
||||
# Update external vnic if addr or mask is changed
|
||||
if orgaddr != newaddr or orgmask != newmask:
|
||||
edge_utils.update_external_interface(
|
||||
self.edge_manager.update_external_interface(
|
||||
self.nsx_v, context, plr_id,
|
||||
new_ext_net_id, newaddr, newmask)
|
||||
|
||||
|
@ -41,7 +41,8 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
|
||||
context, lrouter, dist=False, appliance_size=appliance_size,
|
||||
availability_zone=availability_zone)
|
||||
if allow_metadata:
|
||||
self.plugin.metadata_proxy_handler.configure_router_edge(
|
||||
self.plugin.get_metadata_proxy_handler(
|
||||
availability_zone.name).configure_router_edge(
|
||||
context, lrouter['id'])
|
||||
|
||||
def update_router(self, context, router_id, router):
|
||||
@ -78,8 +79,10 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
|
||||
def detach_router(self, context, router_id, router):
|
||||
LOG.debug("Detach exclusive router id %s", router_id)
|
||||
self.edge_manager.unbind_router_on_edge(context, router_id)
|
||||
metadata_proxy_handler = self.plugin.metadata_proxy_handler
|
||||
if metadata_proxy_handler:
|
||||
if self.plugin.metadata_proxy_handler:
|
||||
az = self.get_router_az_by_id(context, router_id)
|
||||
metadata_proxy_handler = self.plugin.get_metadata_proxy_handler(
|
||||
az.name)
|
||||
metadata_proxy_handler.cleanup_router_edge(context, router_id)
|
||||
|
||||
def _build_router_data_from_db(self, router_db, router):
|
||||
@ -130,8 +133,9 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
|
||||
|
||||
def delete_router(self, context, router_id):
|
||||
if self.plugin.metadata_proxy_handler:
|
||||
self.plugin.metadata_proxy_handler.cleanup_router_edge(
|
||||
context, router_id)
|
||||
az = self.get_router_az_by_id(context, router_id)
|
||||
md_proxy = self.plugin.get_metadata_proxy_handler(az.name)
|
||||
md_proxy.cleanup_router_edge(context, router_id)
|
||||
self.edge_manager.delete_lrouter(context, router_id, dist=False)
|
||||
|
||||
def update_routes(self, context, router_id, nexthop):
|
||||
@ -168,7 +172,7 @@ class RouterExclusiveDriver(router_driver.RouterBaseDriver):
|
||||
|
||||
# Update external vnic if addr or mask is changed
|
||||
if orgaddr != newaddr or orgmask != newmask or force_update:
|
||||
edge_utils.update_external_interface(
|
||||
self.edge_manager.update_external_interface(
|
||||
self.nsx_v, context, router_id,
|
||||
new_ext_net_id, newaddr, newmask)
|
||||
|
||||
|
@ -274,7 +274,7 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
|
||||
'primaryAddress: %s, netmask: %s, nexthop: %s, secondary: '
|
||||
'%s.', ext_net_id, gateway_primary_addr, gateway_mask,
|
||||
gateway_nexthop, secondary)
|
||||
edge_utils.update_external_interface(
|
||||
self.edge_manager.update_external_interface(
|
||||
self.nsx_v, context, target_router_id, ext_net_id,
|
||||
gateway_primary_addr, gateway_mask, secondary)
|
||||
|
||||
@ -552,7 +552,7 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
|
||||
ports_qry = context.session.query(models_v2.Port)
|
||||
all_gw_ports = ports_qry.filter_by(
|
||||
device_owner=l3_db.DEVICE_OWNER_ROUTER_GW).all()
|
||||
metadata_nets = nsxv_db.get_nsxv_internal_network(
|
||||
metadata_nets = nsxv_db.get_nsxv_internal_networks(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
metadata_net_ids = [metadata_net['network_id']
|
||||
@ -592,10 +592,10 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
|
||||
conflict_router_ids, conflict_network_ids,
|
||||
intf_num, az)
|
||||
# configure metadata service on the router.
|
||||
metadata_proxy_handler = self.plugin.metadata_proxy_handler
|
||||
if metadata_proxy_handler and new:
|
||||
metadata_proxy_handler.configure_router_edge(context,
|
||||
router_id)
|
||||
if self.plugin.metadata_proxy_handler and new:
|
||||
md_proxy_handler = self.plugin.get_metadata_proxy_handler(
|
||||
az.name)
|
||||
md_proxy_handler.configure_router_edge(context, router_id)
|
||||
edge_id = edge_utils.get_router_edge_id(context, router_id)
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
# add all internal interfaces of the router on edge
|
||||
@ -618,11 +618,13 @@ class RouterSharedDriver(router_driver.RouterBaseDriver):
|
||||
flavor_id, edge_id)
|
||||
|
||||
def _unbind_router_on_edge(self, context, router_id):
|
||||
az = self.get_router_az_by_id(context, router_id)
|
||||
self.edge_manager.reconfigure_shared_edge_metadata_port(
|
||||
context, router_id)
|
||||
self.edge_manager.unbind_router_on_edge(context, router_id)
|
||||
metadata_proxy_handler = self.plugin.metadata_proxy_handler
|
||||
if metadata_proxy_handler:
|
||||
if self.plugin.metadata_proxy_handler:
|
||||
metadata_proxy_handler = self.plugin.get_metadata_proxy_handler(
|
||||
az.name)
|
||||
metadata_proxy_handler.cleanup_router_edge(context, router_id)
|
||||
|
||||
def _add_router_services_on_available_edge(self, context, router_id):
|
||||
|
@ -92,22 +92,26 @@ def get_router_fw_rules():
|
||||
return fw_rules
|
||||
|
||||
|
||||
def get_db_internal_edge_ips(context):
|
||||
def get_db_internal_edge_ips(context, az_name):
|
||||
ip_list = []
|
||||
edge_list = nsxv_db.get_nsxv_internal_edges_by_purpose(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
|
||||
if edge_list:
|
||||
ip_list = [edge['ext_ip_address'] for edge in edge_list]
|
||||
# Take only the edges on this availability zone
|
||||
ip_list = [edge['ext_ip_address'] for edge in edge_list
|
||||
if nsxv_db.get_router_availability_zone(
|
||||
context.session, edge['router_id']) == az_name]
|
||||
return ip_list
|
||||
|
||||
|
||||
class NsxVMetadataProxyHandler(object):
|
||||
|
||||
def __init__(self, nsxv_plugin):
|
||||
"""A metadata proxy handler for a specific availability zone"""
|
||||
def __init__(self, nsxv_plugin, availability_zone):
|
||||
self.nsxv_plugin = nsxv_plugin
|
||||
context = neutron_context.get_admin_context()
|
||||
self.az = availability_zone
|
||||
|
||||
# Init cannot run concurrently on multiple nodes
|
||||
with locking.LockManager.get_lock('nsx-metadata-init'):
|
||||
@ -119,11 +123,14 @@ class NsxVMetadataProxyHandler(object):
|
||||
def _create_metadata_internal_network(self, context, cidr):
|
||||
# Neutron requires a network to have some tenant_id
|
||||
tenant_id = nsxv_constants.INTERNAL_TENANT_ID
|
||||
|
||||
net_data = {'network': {'name': 'inter-edge-net',
|
||||
net_name = 'inter-edge-net'
|
||||
if not self.az.is_default():
|
||||
net_name = '%s-%s' % (net_name, self.az.name)
|
||||
net_data = {'network': {'name': net_name,
|
||||
'admin_state_up': True,
|
||||
'port_security_enabled': False,
|
||||
'shared': False,
|
||||
'availability_zone_hints': [self.az.name],
|
||||
'tenant_id': tenant_id}}
|
||||
net = self.nsxv_plugin.create_network(context, net_data)
|
||||
|
||||
@ -145,17 +152,21 @@ class NsxVMetadataProxyHandler(object):
|
||||
|
||||
return net['id'], subnet['id']
|
||||
|
||||
def _get_internal_net_by_az(self, context):
|
||||
# Get the internal network for the current az
|
||||
int_net = nsxv_db.get_nsxv_internal_network(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE,
|
||||
self.az.name)
|
||||
|
||||
if int_net:
|
||||
return int_net['network_id']
|
||||
|
||||
def _get_internal_network_and_subnet(self, context):
|
||||
internal_net = None
|
||||
internal_subnet = None
|
||||
|
||||
# Try to find internal net, internal subnet. If not found, create new
|
||||
net_list = nsxv_db.get_nsxv_internal_network(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
|
||||
if net_list:
|
||||
internal_net = net_list[0]['network_id']
|
||||
internal_net = self._get_internal_net_by_az(context)
|
||||
internal_subnet = None
|
||||
|
||||
if internal_net:
|
||||
internal_subnet = self.nsxv_plugin.get_subnets(
|
||||
@ -173,7 +184,8 @@ class NsxVMetadataProxyHandler(object):
|
||||
except Exception as e:
|
||||
nsxv_db.delete_nsxv_internal_network(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE,
|
||||
internal_net)
|
||||
|
||||
# if network is created, clean up
|
||||
if internal_net:
|
||||
@ -188,6 +200,7 @@ class NsxVMetadataProxyHandler(object):
|
||||
nsxv_db.create_nsxv_internal_network(
|
||||
context.session,
|
||||
nsxv_constants.INTER_EDGE_PURPOSE,
|
||||
self.az.name,
|
||||
internal_net)
|
||||
else:
|
||||
error = _('Metadata initialization is incomplete on '
|
||||
@ -223,29 +236,30 @@ class NsxVMetadataProxyHandler(object):
|
||||
def _get_proxy_edges(self, context):
|
||||
proxy_edge_ips = []
|
||||
|
||||
db_edge_ips = get_db_internal_edge_ips(context)
|
||||
if len(db_edge_ips) > len(cfg.CONF.nsxv.mgt_net_proxy_ips):
|
||||
error = _('Number of configured metadata proxy IPs is smaller '
|
||||
'than number of Edges which are already provisioned')
|
||||
db_edge_ips = get_db_internal_edge_ips(context, self.az.name)
|
||||
if len(db_edge_ips) > len(self.az.mgt_net_proxy_ips):
|
||||
error = (_('Number of configured metadata proxy IPs is smaller '
|
||||
'than number of Edges which are already provisioned '
|
||||
'for availability zone %s'), self.az.name)
|
||||
raise nsxv_exc.NsxPluginException(err_msg=error)
|
||||
|
||||
pool = eventlet.GreenPool(min(MAX_INIT_THREADS,
|
||||
len(cfg.CONF.nsxv.mgt_net_proxy_ips)))
|
||||
len(self.az.mgt_net_proxy_ips)))
|
||||
|
||||
# Edge IPs that exist in both lists have to be validated that their
|
||||
# Edge appliance settings are valid
|
||||
for edge_inner_ip in pool.imap(
|
||||
self._setup_proxy_edge_route_and_connectivity,
|
||||
list(set(db_edge_ips) & set(cfg.CONF.nsxv.mgt_net_proxy_ips))):
|
||||
list(set(db_edge_ips) & set(self.az.mgt_net_proxy_ips))):
|
||||
proxy_edge_ips.append(edge_inner_ip)
|
||||
|
||||
# Edges that exist only in the CFG list, should be paired with Edges
|
||||
# that exist only in the DB list. The existing Edge from the list will
|
||||
# be reconfigured to match the new config
|
||||
edge_to_convert_ips = (
|
||||
list(set(db_edge_ips) - set(cfg.CONF.nsxv.mgt_net_proxy_ips)))
|
||||
list(set(db_edge_ips) - set(self.az.mgt_net_proxy_ips)))
|
||||
edge_ip_to_set = (
|
||||
list(set(cfg.CONF.nsxv.mgt_net_proxy_ips) - set(db_edge_ips)))
|
||||
list(set(self.az.mgt_net_proxy_ips) - set(db_edge_ips)))
|
||||
|
||||
if edge_to_convert_ips:
|
||||
if cfg.CONF.nsxv.metadata_initializer:
|
||||
@ -283,6 +297,12 @@ class NsxVMetadataProxyHandler(object):
|
||||
rtr_id = self._get_edge_rtr_id_by_ext_ip(context, rtr_ext_ip)
|
||||
if not edge_id:
|
||||
edge_id = self._get_edge_id_by_rtr_id(context, rtr_id)
|
||||
if not rtr_id or not edge_id:
|
||||
# log this error and return without the ip, but don't fail
|
||||
LOG.error(_LE("Failed find edge for router %(rtr_id)s with ip "
|
||||
"%(rtr_ext_ip)s"),
|
||||
{'rtr_id': rtr_id, 'rtr_ext_ip': rtr_ext_ip})
|
||||
return
|
||||
|
||||
# Read and validate DGW. If different, replace with new value
|
||||
try:
|
||||
@ -297,11 +317,11 @@ class NsxVMetadataProxyHandler(object):
|
||||
|
||||
dgw = routes.get('defaultRoute', {}).get('gatewayAddress')
|
||||
|
||||
if dgw != cfg.CONF.nsxv.mgt_net_default_gateway:
|
||||
if dgw != self.az.mgt_net_default_gateway:
|
||||
if cfg.CONF.nsxv.metadata_initializer:
|
||||
self.nsxv_plugin._update_routes(
|
||||
context, rtr_id,
|
||||
cfg.CONF.nsxv.mgt_net_default_gateway)
|
||||
self.az.mgt_net_default_gateway)
|
||||
else:
|
||||
error = _('Metadata initialization is incomplete on '
|
||||
'initializer node')
|
||||
@ -314,16 +334,16 @@ class NsxVMetadataProxyHandler(object):
|
||||
).get('addressGroups', {}
|
||||
)[0].get('primaryAddress')
|
||||
cur_pgroup = if_data['portgroupId']
|
||||
if (if_data and cur_pgroup != cfg.CONF.nsxv.mgt_net_moid
|
||||
if (if_data and cur_pgroup != self.az.mgt_net_moid
|
||||
or cur_ip != rtr_ext_ip):
|
||||
if cfg.CONF.nsxv.metadata_initializer:
|
||||
self.nsxv_plugin.nsx_v.update_interface(
|
||||
rtr_id,
|
||||
edge_id,
|
||||
vcns_const.EXTERNAL_VNIC_INDEX,
|
||||
cfg.CONF.nsxv.mgt_net_moid,
|
||||
self.az.mgt_net_moid,
|
||||
address=rtr_ext_ip,
|
||||
netmask=cfg.CONF.nsxv.mgt_net_proxy_netmask,
|
||||
netmask=self.az.mgt_net_proxy_netmask,
|
||||
secondary=[])
|
||||
else:
|
||||
error = _('Metadata initialization is incomplete on '
|
||||
@ -397,12 +417,17 @@ class NsxVMetadataProxyHandler(object):
|
||||
context = neutron_context.get_admin_context()
|
||||
|
||||
rtr_id = None
|
||||
|
||||
try:
|
||||
rtr_name = 'metadata_proxy_router'
|
||||
if not self.az.is_default():
|
||||
rtr_name = '%s-%s' % (rtr_name, self.az.name)
|
||||
router_data = {
|
||||
'router': {
|
||||
'name': 'metadata_proxy_router',
|
||||
'name': rtr_name,
|
||||
'admin_state_up': True,
|
||||
'router_type': 'exclusive',
|
||||
'availability_zone_hints': [self.az.name],
|
||||
'tenant_id': nsxv_constants.INTERNAL_TENANT_ID}}
|
||||
|
||||
rtr = self.nsxv_plugin.create_router(
|
||||
@ -417,9 +442,9 @@ class NsxVMetadataProxyHandler(object):
|
||||
rtr['id'],
|
||||
edge_id,
|
||||
vcns_const.EXTERNAL_VNIC_INDEX,
|
||||
cfg.CONF.nsxv.mgt_net_moid,
|
||||
self.az.mgt_net_moid,
|
||||
address=rtr_ext_ip,
|
||||
netmask=cfg.CONF.nsxv.mgt_net_proxy_netmask,
|
||||
netmask=self.az.mgt_net_proxy_netmask,
|
||||
secondary=[])
|
||||
|
||||
port_data = {
|
||||
@ -465,10 +490,10 @@ class NsxVMetadataProxyHandler(object):
|
||||
{'firewall_rule_list': firewall_rules},
|
||||
allow_external=False)
|
||||
|
||||
if cfg.CONF.nsxv.mgt_net_default_gateway:
|
||||
if self.az.mgt_net_default_gateway:
|
||||
self.nsxv_plugin._update_routes(
|
||||
context, rtr_id,
|
||||
cfg.CONF.nsxv.mgt_net_default_gateway)
|
||||
self.az.mgt_net_default_gateway)
|
||||
|
||||
nsxv_db.create_nsxv_internal_edge(
|
||||
context.session, rtr_ext_ip,
|
||||
|
@ -292,11 +292,27 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
and cfg.CONF.nsxv.mgt_net_proxy_ips
|
||||
and cfg.CONF.nsxv.mgt_net_proxy_netmask)
|
||||
if has_metadata_cfg:
|
||||
self.metadata_proxy_handler = (
|
||||
nsx_v_md_proxy.NsxVMetadataProxyHandler(self))
|
||||
# Init md_proxy handler per availability zone
|
||||
self.metadata_proxy_handler = {}
|
||||
az_list = self._availability_zones_data.list_availability_zones()
|
||||
for name in az_list:
|
||||
az = self._availability_zones_data.get_availability_zone(name)
|
||||
# create metadata handler only if the az supports it.
|
||||
# if not, the global one will be used
|
||||
if az.supports_metadata():
|
||||
self.metadata_proxy_handler[name] = (
|
||||
nsx_v_md_proxy.NsxVMetadataProxyHandler(self, az))
|
||||
|
||||
self.init_is_complete = True
|
||||
|
||||
def get_metadata_proxy_handler(self, az_name):
|
||||
if not self.metadata_proxy_handler:
|
||||
return None
|
||||
if az_name in self.metadata_proxy_handler:
|
||||
return self.metadata_proxy_handler[az_name]
|
||||
# fallback to the global handler
|
||||
return self.metadata_proxy_handler[nsx_az.DEFAULT_NAME]
|
||||
|
||||
def add_vms_to_service_insertion(self, sg_id):
|
||||
def _add_vms_to_service_insertion(*args, **kwargs):
|
||||
|
||||
@ -545,13 +561,27 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
if err_msg:
|
||||
raise n_exc.InvalidInput(error_message=err_msg)
|
||||
|
||||
def _validate_physical_network(self, physical_network):
|
||||
dvs_ids = self._get_dvs_ids(physical_network)
|
||||
def _validate_physical_network(self, physical_network, default_dvs):
|
||||
dvs_ids = self._get_dvs_ids(physical_network, default_dvs)
|
||||
for dvs_id in dvs_ids:
|
||||
if not self.nsx_v.vcns.validate_dvs(dvs_id):
|
||||
raise nsx_exc.NsxResourceNotFound(res_name='dvs_id',
|
||||
res_id=dvs_id)
|
||||
|
||||
def _get_network_az_from_net_data(self, net_data):
|
||||
if az_ext.AZ_HINTS in net_data and net_data[az_ext.AZ_HINTS]:
|
||||
return self._availability_zones_data.get_availability_zone(
|
||||
net_data[az_ext.AZ_HINTS][0])
|
||||
return self.get_default_az()
|
||||
|
||||
def _get_network_az_dvs_id(self, net_data):
|
||||
az = self._get_network_az_from_net_data(net_data)
|
||||
return az.dvs_id
|
||||
|
||||
def _get_network_vdn_scope_id(self, net_data):
|
||||
az = self._get_network_az_from_net_data(net_data)
|
||||
return az.vdn_scope_id
|
||||
|
||||
def _validate_provider_create(self, context, network):
|
||||
if not validators.is_attr_set(network.get(mpnet.SEGMENTS)):
|
||||
return
|
||||
@ -563,6 +593,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
network_type_set = validators.is_attr_set(network_type)
|
||||
segmentation_id_set = validators.is_attr_set(segmentation_id)
|
||||
physical_network_set = validators.is_attr_set(physical_network)
|
||||
az_dvs = self._get_network_az_dvs_id(network)
|
||||
|
||||
err_msg = None
|
||||
if not network_type_set:
|
||||
@ -572,7 +603,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
err_msg = _("Segmentation ID cannot be specified with "
|
||||
"flat network type")
|
||||
if physical_network_set:
|
||||
self._validate_physical_network(physical_network)
|
||||
self._validate_physical_network(physical_network, az_dvs)
|
||||
elif network_type == c_utils.NsxVNetworkTypes.VLAN:
|
||||
if not segmentation_id_set:
|
||||
err_msg = _("Segmentation ID must be specified with "
|
||||
@ -589,8 +620,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
bindings = nsxv_db.get_network_bindings_by_vlanid(
|
||||
context.session, segmentation_id)
|
||||
if bindings:
|
||||
phy_uuid = (physical_network if physical_network_set
|
||||
else self.dvs_id)
|
||||
if physical_network_set:
|
||||
phy_uuid = physical_network
|
||||
else:
|
||||
# use the fvs_id of the availability zone
|
||||
phy_uuid = az_dvs
|
||||
for binding in bindings:
|
||||
if binding['phy_uuid'] == phy_uuid:
|
||||
raise n_exc.VlanIdInUse(
|
||||
@ -598,7 +632,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
physical_network=phy_uuid)
|
||||
# Verify whether the DVSes exist in the backend.
|
||||
if physical_network_set:
|
||||
self._validate_physical_network(physical_network)
|
||||
self._validate_physical_network(physical_network, az_dvs)
|
||||
|
||||
elif network_type == c_utils.NsxVNetworkTypes.VXLAN:
|
||||
# Currently unable to set the segmentation id
|
||||
@ -810,7 +844,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
self._update_network_teaming(dvs_id, net_data['id'], c)
|
||||
return c
|
||||
|
||||
def _get_dvs_ids(self, physical_network):
|
||||
def _get_dvs_ids(self, physical_network, default_dvs):
|
||||
"""Extract DVS-IDs provided in the physical network field.
|
||||
|
||||
If physical network attribute is not set, return the pre configured
|
||||
@ -818,7 +852,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
to a list of unique DVS-IDs.
|
||||
"""
|
||||
if not validators.is_attr_set(physical_network):
|
||||
return [self.dvs_id]
|
||||
return [default_dvs]
|
||||
# Return unique DVS-IDs only and ignore duplicates
|
||||
return list(set(
|
||||
dvs.strip() for dvs in physical_network.split(',') if dvs))
|
||||
@ -946,7 +980,11 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
return self.get_default_az()
|
||||
|
||||
def get_network_az(self, context, network_id):
|
||||
try:
|
||||
network = self.get_network(context, network_id)
|
||||
except Exception:
|
||||
return self.get_default_az()
|
||||
|
||||
return self.get_network_or_router_az(network)
|
||||
|
||||
def get_router_az(self, router):
|
||||
@ -995,7 +1033,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
virtual_wire = {"name": net_data['id'],
|
||||
"tenantId": "virtual wire tenant"}
|
||||
config_spec = {"virtualWireCreateSpec": virtual_wire}
|
||||
vdn_scope_id = self.vdn_scope_id
|
||||
vdn_scope_id = self._get_network_vdn_scope_id(net_data)
|
||||
if provider_type is not None:
|
||||
segment = net_data[mpnet.SEGMENTS][0]
|
||||
if validators.is_attr_set(
|
||||
@ -1020,7 +1058,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
# Retrieve the list of dvs-ids from physical network.
|
||||
# If physical_network attr is not set, retrieve a list
|
||||
# consisting of a single dvs-id pre-configured in nsx.ini
|
||||
dvs_ids = self._get_dvs_ids(physical_network)
|
||||
az_dvs = self._get_network_az_dvs_id(net_data)
|
||||
dvs_ids = self._get_dvs_ids(physical_network, az_dvs)
|
||||
dvs_net_ids = []
|
||||
# Save the list of netmorefs from the backend
|
||||
net_morefs = []
|
||||
@ -1062,8 +1101,6 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
|
||||
# update the network with the availability zone hints
|
||||
if az_ext.AZ_HINTS in net_data:
|
||||
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])
|
||||
super(NsxVPluginV2, self).update_network(context,
|
||||
@ -1089,7 +1126,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
physical_net_set = validators.is_attr_set(
|
||||
physical_network)
|
||||
if not physical_net_set:
|
||||
physical_network = self.dvs_id
|
||||
# Use the dvs_id of the availability zone
|
||||
physical_network = self._get_network_az_dvs_id(
|
||||
net_data)
|
||||
net_bindings.append(nsxv_db.add_network_binding(
|
||||
context.session, new_net['id'],
|
||||
network_type,
|
||||
@ -1190,8 +1229,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
context.session, dhcp_edge['edge_id'])
|
||||
if rtr_binding:
|
||||
rtr_id = rtr_binding['router_id']
|
||||
self.metadata_proxy_handler.cleanup_router_edge(
|
||||
context, rtr_id)
|
||||
az_name = rtr_binding['availability_zone']
|
||||
md_proxy = self.get_metadata_proxy_handler(az_name)
|
||||
md_proxy.cleanup_router_edge(context, rtr_id)
|
||||
else:
|
||||
self.edge_manager.reconfigure_shared_edge_metadata_port(
|
||||
context, (vcns_const.DHCP_EDGE_PREFIX + net_id)[:36])
|
||||
@ -1307,7 +1347,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
[db_utils.resource_fields(network,
|
||||
fields) for network in networks])
|
||||
|
||||
def _raise_if_updates_provider_attributes(self, original_network, attrs):
|
||||
def _raise_if_updates_provider_attributes(self, original_network, attrs,
|
||||
az_dvs):
|
||||
"""Raise exception if provider attributes are present.
|
||||
|
||||
For the NSX-V we want to allow changing the physical network of
|
||||
@ -1322,11 +1363,12 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
and not validators.is_attr_set(
|
||||
attrs.get(providernet.SEGMENTATION_ID))):
|
||||
self._validate_physical_network(
|
||||
attrs[providernet.PHYSICAL_NETWORK])
|
||||
attrs[providernet.PHYSICAL_NETWORK], az_dvs)
|
||||
return
|
||||
providernet._raise_if_updates_provider_attributes(attrs)
|
||||
|
||||
def _update_vlan_network_dvs_ids(self, network, new_physical_network):
|
||||
def _update_vlan_network_dvs_ids(self, network, new_physical_network,
|
||||
az_dvs):
|
||||
"""Update the dvs ids of a vlan provider network
|
||||
|
||||
The new values will be added to the current ones.
|
||||
@ -1345,9 +1387,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
dvs_pg_mappings = {}
|
||||
|
||||
current_dvs_ids = set(self._get_dvs_ids(
|
||||
network[providernet.PHYSICAL_NETWORK]))
|
||||
network[providernet.PHYSICAL_NETWORK], az_dvs))
|
||||
new_dvs_ids = set(self._get_dvs_ids(
|
||||
new_physical_network))
|
||||
new_physical_network, az_dvs))
|
||||
additinal_dvs_ids = new_dvs_ids - current_dvs_ids
|
||||
|
||||
if not additinal_dvs_ids:
|
||||
@ -1374,8 +1416,9 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
def update_network(self, context, id, network):
|
||||
net_attrs = network['network']
|
||||
orig_net = self.get_network(context, id)
|
||||
az_dvs = self._get_network_az_dvs_id(orig_net)
|
||||
self._raise_if_updates_provider_attributes(
|
||||
orig_net, net_attrs)
|
||||
orig_net, net_attrs, az_dvs)
|
||||
if net_attrs.get("admin_state_up") is False:
|
||||
raise NotImplementedError(_("admin_state_up=False networks "
|
||||
"are not supported."))
|
||||
@ -1402,7 +1445,8 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
(updated_morefs,
|
||||
new_dvs_pg_mappings) = self._update_vlan_network_dvs_ids(
|
||||
orig_net,
|
||||
net_attrs[providernet.PHYSICAL_NETWORK])
|
||||
net_attrs[providernet.PHYSICAL_NETWORK],
|
||||
az_dvs)
|
||||
if updated_morefs:
|
||||
new_dvs = list(new_dvs_pg_mappings.values())
|
||||
net_morefs.extend(new_dvs)
|
||||
@ -2436,15 +2480,24 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
if binding:
|
||||
return binding['edge_id']
|
||||
|
||||
def _get_edge_id_and_az_by_rtr_id(self, context, rtr_id):
|
||||
binding = nsxv_db.get_nsxv_router_binding(
|
||||
context.session,
|
||||
rtr_id)
|
||||
|
||||
if binding:
|
||||
return binding['edge_id'], binding['availability_zone']
|
||||
|
||||
def _update_dhcp_service_new_edge(self, context, resource_id):
|
||||
edge_id = self._get_edge_id_by_rtr_id(context, resource_id)
|
||||
edge_id, az_name = self._get_edge_id_and_az_by_rtr_id(
|
||||
context, resource_id)
|
||||
if edge_id:
|
||||
with locking.LockManager.get_lock(str(edge_id)):
|
||||
if self.metadata_proxy_handler:
|
||||
LOG.debug('Update metadata for resource %s',
|
||||
resource_id)
|
||||
self.metadata_proxy_handler.configure_router_edge(
|
||||
context, resource_id)
|
||||
LOG.debug('Update metadata for resource %s az=%s',
|
||||
resource_id, az_name)
|
||||
md_proxy = self.get_metadata_proxy_handler(az_name)
|
||||
md_proxy.configure_router_edge(context, resource_id)
|
||||
|
||||
self.setup_dhcp_edge_fw_rules(context, self,
|
||||
resource_id)
|
||||
@ -2839,23 +2892,29 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
return self._get_network_availability_zones(context, net_db)
|
||||
|
||||
def _get_network_availability_zones(self, context, net_db):
|
||||
"""Return availability zones which a network belongs to."""
|
||||
"""Return availability zones which a network belongs to.
|
||||
|
||||
Return only the actual az the dhcp edge is deployed on.
|
||||
If there is no edge - the availability zones list is empty.
|
||||
"""
|
||||
resource_id = (vcns_const.DHCP_EDGE_PREFIX + net_db["id"])[:36]
|
||||
dhcp_edge_binding = nsxv_db.get_nsxv_router_binding(
|
||||
context.session, resource_id)
|
||||
if dhcp_edge_binding:
|
||||
edge_id = dhcp_edge_binding['edge_id']
|
||||
return [self._get_availability_zone_name_by_edge(
|
||||
context, edge_id)]
|
||||
return [dhcp_edge_binding['availability_zone']]
|
||||
return []
|
||||
|
||||
def get_router_availability_zones(self, router):
|
||||
"""Return availability zones which a router belongs to."""
|
||||
"""Return availability zones which a router belongs to.
|
||||
|
||||
Return only the actual az the router edge is deployed on.
|
||||
If there is no edge - the availability zones list is empty.
|
||||
"""
|
||||
context = n_context.get_admin_context()
|
||||
edge_id = self._get_edge_id_by_rtr_id(context, router["id"])
|
||||
if edge_id:
|
||||
return [self._get_availability_zone_name_by_edge(
|
||||
context, edge_id)]
|
||||
binding = nsxv_db.get_nsxv_router_binding(
|
||||
context.session, router['id'])
|
||||
if binding:
|
||||
return [binding['availability_zone']]
|
||||
return []
|
||||
|
||||
def _process_router_flavor_create(self, context, router_db, r):
|
||||
@ -3192,7 +3251,7 @@ class NsxVPluginV2(addr_pair_db.AllowedAddressPairsMixin,
|
||||
secondary = self._get_floatingips_by_router(context, router['id'])
|
||||
if not router_id:
|
||||
router_id = router['id']
|
||||
edge_utils.update_external_interface(
|
||||
self.edge_manager.update_external_interface(
|
||||
self.nsx_v, context, router_id, ext_net_id,
|
||||
addr, mask, secondary)
|
||||
|
||||
|
@ -397,11 +397,11 @@ class EdgeApplianceDriver(object):
|
||||
if not dist:
|
||||
vnic_external = self._assemble_edge_vnic(
|
||||
constants.EXTERNAL_VNIC_NAME, constants.EXTERNAL_VNIC_INDEX,
|
||||
self.external_network, type="uplink")
|
||||
availability_zone.external_network, type="uplink")
|
||||
edge['vnics']['vnics'].append(vnic_external)
|
||||
else:
|
||||
edge['mgmtInterface'] = {
|
||||
'connectedToId': self.external_network,
|
||||
'connectedToId': availability_zone.external_network,
|
||||
'name': "mgmtInterface"}
|
||||
if internal_network:
|
||||
vnic_inside = self._assemble_edge_vnic(
|
||||
@ -470,11 +470,11 @@ class EdgeApplianceDriver(object):
|
||||
if not dist:
|
||||
vnic_external = self._assemble_edge_vnic(
|
||||
constants.EXTERNAL_VNIC_NAME, constants.EXTERNAL_VNIC_INDEX,
|
||||
self.external_network, type="uplink")
|
||||
availability_zone.external_network, type="uplink")
|
||||
edge['vnics']['vnics'].append(vnic_external)
|
||||
else:
|
||||
edge['mgmtInterface'] = {
|
||||
'connectedToId': self.external_network,
|
||||
'connectedToId': availability_zone.external_network,
|
||||
'name': "mgmtInterface"}
|
||||
|
||||
if internal_network:
|
||||
|
@ -184,7 +184,6 @@ class EdgeManager(object):
|
||||
self._worker_pool_pid = None
|
||||
self._worker_pool = None
|
||||
self.nsxv_manager = nsxv_manager
|
||||
self.dvs_id = cfg.CONF.nsxv.dvs_id
|
||||
self._availability_zones = nsx_az.ConfiguredAvailabilityZones()
|
||||
self.edge_pool_dicts = self._parse_backup_edge_pool_opt()
|
||||
self.nsxv_plugin = nsxv_manager.callbacks.plugin
|
||||
@ -444,10 +443,11 @@ class EdgeManager(object):
|
||||
return router_binding
|
||||
backup_router_bindings.remove(router_binding)
|
||||
|
||||
def _get_physical_provider_network(self, context, network_id):
|
||||
def _get_physical_provider_network(self, context, network_id, az_dvs):
|
||||
bindings = nsxv_db.get_network_bindings(context.session, network_id)
|
||||
# Set the return value as global DVS-ID of the mgmt/edge cluster
|
||||
phys_net = self.dvs_id
|
||||
# Set the return value as the availability zone DVS-ID of the
|
||||
# mgmt/edge cluster
|
||||
phys_net = az_dvs
|
||||
network_type = None
|
||||
if bindings:
|
||||
binding = bindings[0]
|
||||
@ -471,7 +471,9 @@ class EdgeManager(object):
|
||||
def _create_sub_interface(self, context, network_id, network_name,
|
||||
tunnel_index, address_groups,
|
||||
port_group_id=None):
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, network_id)
|
||||
az = self.plugin.get_network_az(context, network_id)
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, network_id,
|
||||
az.name)
|
||||
if port_group_id is None:
|
||||
portgroup = {'vlanId': 0,
|
||||
'networkName': network_name,
|
||||
@ -479,7 +481,7 @@ class EdgeManager(object):
|
||||
'networkType': 'Isolation'}
|
||||
config_spec = {'networkSpec': portgroup}
|
||||
dvs_id, network_type = self._get_physical_provider_network(
|
||||
context, network_id)
|
||||
context, network_id, az.dvs_id)
|
||||
pg, port_group_id = self.nsxv_manager.vcns.create_port_group(
|
||||
dvs_id, config_spec)
|
||||
# Ensure that the portgroup has the correct teaming
|
||||
@ -522,8 +524,9 @@ class EdgeManager(object):
|
||||
header, _ = self.nsxv_manager.vcns.delete_interface(edge_id,
|
||||
vnic_index)
|
||||
if port_group_id:
|
||||
az = self.plugin.get_network_az(context, network_id)
|
||||
dvs_id, net_type = self._get_physical_provider_network(
|
||||
context, network_id)
|
||||
context, network_id, az.dvs_id)
|
||||
self.nsxv_manager.delete_port_group(dvs_id,
|
||||
port_group_id)
|
||||
else:
|
||||
@ -546,17 +549,20 @@ class EdgeManager(object):
|
||||
"""Delete the router binding or clean the edge appliance."""
|
||||
|
||||
resource_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||
bindings = nsxv_db.get_nsxv_router_bindings(context.session)
|
||||
all_dhcp_edges = {binding['router_id']: binding['edge_id'] for
|
||||
bindings = nsxv_db.get_nsxv_router_bindings_by_edge(
|
||||
context.session, edge_id)
|
||||
all_edge_dhcp_entries = [binding['router_id'] for
|
||||
binding in bindings if binding['router_id'].
|
||||
startswith(vcns_const.DHCP_EDGE_PREFIX)}
|
||||
for router_id in all_dhcp_edges:
|
||||
if (router_id != resource_id and
|
||||
all_dhcp_edges[router_id] == edge_id):
|
||||
startswith(vcns_const.DHCP_EDGE_PREFIX)]
|
||||
for router_id in all_edge_dhcp_entries:
|
||||
if (router_id != resource_id):
|
||||
# There are additional networks on this DHCP edge.
|
||||
# just delete the binding one and not the edge itself
|
||||
nsxv_db.delete_nsxv_router_binding(context.session,
|
||||
resource_id)
|
||||
return
|
||||
self._free_dhcp_edge_appliance(context, network_id)
|
||||
az_name = bindings[0]['availability_zone'] if bindings else ''
|
||||
self._free_dhcp_edge_appliance(context, network_id, az_name)
|
||||
|
||||
def _addr_groups_convert_to_ipset(self, address_groups):
|
||||
cidr_list = []
|
||||
@ -823,12 +829,13 @@ class EdgeManager(object):
|
||||
appliance_size=appliance_size,
|
||||
availability_zone=availability_zone)
|
||||
|
||||
def _free_dhcp_edge_appliance(self, context, network_id):
|
||||
def _free_dhcp_edge_appliance(self, context, network_id, az_name):
|
||||
router_id = (vcns_const.DHCP_EDGE_PREFIX + network_id)[:36]
|
||||
|
||||
# if there are still metadata ports on this edge - delete them now
|
||||
metadata_proxy_handler = self.plugin.metadata_proxy_handler
|
||||
if metadata_proxy_handler:
|
||||
if self.plugin.metadata_proxy_handler:
|
||||
metadata_proxy_handler = self.plugin.get_metadata_proxy_handler(
|
||||
az_name)
|
||||
metadata_proxy_handler.cleanup_router_edge(context, router_id,
|
||||
warn=True)
|
||||
|
||||
@ -1183,23 +1190,31 @@ class EdgeManager(object):
|
||||
appliance_size=app_size,
|
||||
availability_zone=availability_zone.name)
|
||||
nsxv_db.allocate_edge_vnic_with_tunnel_index(
|
||||
context.session, edge_id, network_id)
|
||||
context.session, edge_id, network_id,
|
||||
availability_zone.name)
|
||||
|
||||
def reconfigure_shared_edge_metadata_port(self, context, org_router_id):
|
||||
if not self.plugin.metadata_proxy_handler:
|
||||
return
|
||||
|
||||
net_list = nsxv_db.get_nsxv_internal_network(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
|
||||
if not net_list:
|
||||
org_binding = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
org_router_id)
|
||||
if not org_binding:
|
||||
return
|
||||
internal_net = net_list[0]['network_id']
|
||||
|
||||
az_name = org_binding['availability_zone']
|
||||
int_net = nsxv_db.get_nsxv_internal_network(
|
||||
context.session,
|
||||
vcns_const.InternalEdgePurposes.INTER_EDGE_PURPOSE,
|
||||
az_name)
|
||||
|
||||
if not int_net:
|
||||
return
|
||||
# Query the ports of this internal network
|
||||
internal_nets = [int_net['network_id']]
|
||||
ports = self.nsxv_plugin.get_ports(
|
||||
context, filters={'device_id': [org_router_id],
|
||||
'network_id': [internal_net]})
|
||||
'network_id': internal_nets})
|
||||
|
||||
if not ports:
|
||||
LOG.debug('No metadata ports found for %s', org_router_id)
|
||||
@ -1208,10 +1223,6 @@ class EdgeManager(object):
|
||||
LOG.debug('Expecting one metadata port for %s. Found %d ports',
|
||||
org_router_id, len(ports))
|
||||
|
||||
org_binding = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
org_router_id)
|
||||
|
||||
if org_binding:
|
||||
edge_id = org_binding['edge_id']
|
||||
bindings = nsxv_db.get_nsxv_router_bindings(
|
||||
context.session, filters={'edge_id': [edge_id]})
|
||||
@ -1231,7 +1242,8 @@ class EdgeManager(object):
|
||||
new_edge = nsxv_db.get_nsxv_router_binding(context.session,
|
||||
resource_id)
|
||||
nsxv_db.allocate_edge_vnic_with_tunnel_index(
|
||||
context.session, new_edge['edge_id'], network_id)
|
||||
context.session, new_edge['edge_id'], network_id,
|
||||
availability_zone.name)
|
||||
return new_edge['edge_id']
|
||||
|
||||
def create_dhcp_edge_service(self, context, network_id,
|
||||
@ -1421,9 +1433,9 @@ class EdgeManager(object):
|
||||
# Attach to DHCP Edge
|
||||
dhcp_edge_id = self.allocate_new_dhcp_edge(
|
||||
context, network_id, resource_id, availability_zone)
|
||||
|
||||
self.plugin.metadata_proxy_handler.configure_router_edge(
|
||||
context, resource_id)
|
||||
md_proxy = self.plugin.get_metadata_proxy_handler(
|
||||
availability_zone.name)
|
||||
md_proxy.configure_router_edge(context, resource_id)
|
||||
with locking.LockManager.get_lock(str(dhcp_edge_id)):
|
||||
self.plugin.setup_dhcp_edge_fw_rules(
|
||||
context, self.plugin, resource_id)
|
||||
@ -1659,7 +1671,7 @@ class EdgeManager(object):
|
||||
virtual_wire = {"name": lswitch_name,
|
||||
"tenantId": "virtual wire tenant"}
|
||||
config_spec = {"virtualWireCreateSpec": virtual_wire}
|
||||
vdn_scope_id = cfg.CONF.nsxv.vdn_scope_id
|
||||
vdn_scope_id = availability_zone.vdn_scope_id
|
||||
h, lswitch_id = self.nsxv_manager.vcns.create_virtual_wire(
|
||||
vdn_scope_id, config_spec)
|
||||
|
||||
@ -1997,6 +2009,83 @@ class EdgeManager(object):
|
||||
metainfo = self.plugin.get_flavor_metainfo(context, flavor_id)
|
||||
return metainfo.get('syslog')
|
||||
|
||||
def update_external_interface(
|
||||
self, nsxv_manager, context, router_id, ext_net_id,
|
||||
ipaddr, netmask, secondary=None):
|
||||
with locking.LockManager.get_lock(str(router_id)):
|
||||
self._update_external_interface(nsxv_manager, context, router_id,
|
||||
ext_net_id, ipaddr, netmask,
|
||||
secondary=secondary)
|
||||
|
||||
def _update_external_interface(
|
||||
self, nsxv_manager, context, router_id, ext_net_id,
|
||||
ipaddr, netmask, secondary=None):
|
||||
secondary = secondary or []
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
|
||||
# If no binding was found, no interface to update - exit
|
||||
if not binding:
|
||||
LOG.error(_LE('Edge binding not found for router %s'), router_id)
|
||||
return
|
||||
|
||||
net_bindings = nsxv_db.get_network_bindings(
|
||||
context.session, ext_net_id)
|
||||
if not net_bindings:
|
||||
az_name = binding.availability_zone
|
||||
az = self._availability_zones.get_availability_zone(az_name)
|
||||
vcns_network_id = az.external_network
|
||||
else:
|
||||
vcns_network_id = net_bindings[0].phy_uuid
|
||||
|
||||
# reorganize external vnic's address groups
|
||||
if netmask:
|
||||
address_groups = []
|
||||
addr_list = []
|
||||
for str_cidr in netmask:
|
||||
ip_net = netaddr.IPNetwork(str_cidr)
|
||||
address_group = {'primaryAddress': None,
|
||||
'subnetPrefixLength': str(ip_net.prefixlen)}
|
||||
if (ipaddr not in addr_list and
|
||||
_check_ipnet_ip(ip_net, ipaddr)):
|
||||
address_group['primaryAddress'] = ipaddr
|
||||
addr_list.append(ipaddr)
|
||||
for sec_ip in secondary:
|
||||
if (sec_ip not in addr_list and
|
||||
_check_ipnet_ip(ip_net, sec_ip)):
|
||||
if not address_group['primaryAddress']:
|
||||
address_group['primaryAddress'] = sec_ip
|
||||
else:
|
||||
if not address_group.get('secondaryAddresses'):
|
||||
address_group['secondaryAddresses'] = {
|
||||
'ipAddress': [sec_ip],
|
||||
'type': 'secondary_addresses'}
|
||||
else:
|
||||
address_group['secondaryAddresses'][
|
||||
'ipAddress'].append(sec_ip)
|
||||
addr_list.append(sec_ip)
|
||||
if address_group['primaryAddress']:
|
||||
address_groups.append(address_group)
|
||||
if ipaddr not in addr_list:
|
||||
LOG.error(_LE("primary address %s of ext vnic is not "
|
||||
"configured"), ipaddr)
|
||||
if secondary:
|
||||
missed_ip_sec = set(secondary) - set(addr_list)
|
||||
if missed_ip_sec:
|
||||
LOG.error(_LE("secondary address %s of ext vnic are not "
|
||||
"configured"), str(missed_ip_sec))
|
||||
nsxv_manager.update_interface(router_id, binding['edge_id'],
|
||||
vcns_const.EXTERNAL_VNIC_INDEX,
|
||||
vcns_network_id,
|
||||
address_groups=address_groups)
|
||||
|
||||
else:
|
||||
nsxv_manager.update_interface(router_id, binding['edge_id'],
|
||||
vcns_const.EXTERNAL_VNIC_INDEX,
|
||||
vcns_network_id,
|
||||
address=ipaddr,
|
||||
netmask=netmask,
|
||||
secondary=secondary)
|
||||
|
||||
|
||||
def create_lrouter(nsxv_manager, context, lrouter, lswitch=None, dist=False,
|
||||
availability_zone=None):
|
||||
@ -2040,7 +2129,7 @@ def remove_irrelevant_keys_from_edge_request(edge_request):
|
||||
edge_request.pop(key, None)
|
||||
|
||||
|
||||
def _retrieve_nsx_switch_id(context, network_id):
|
||||
def _retrieve_nsx_switch_id(context, network_id, az_name):
|
||||
"""Helper method to retrieve backend switch ID."""
|
||||
bindings = nsxv_db.get_network_bindings(context.session, network_id)
|
||||
if bindings:
|
||||
@ -2053,8 +2142,10 @@ def _retrieve_nsx_switch_id(context, network_id):
|
||||
else:
|
||||
# If network is of type VLAN and multiple dvs associated with
|
||||
# one neutron network, retrieve the logical network id for the
|
||||
# edge/mgmt cluster's DVS.
|
||||
dvs_id = cfg.CONF.nsxv.dvs_id
|
||||
# edge/mgmt cluster's DVS from the networks availability zone.
|
||||
azs = nsx_az.ConfiguredAvailabilityZones()
|
||||
az = azs.get_availability_zone(az_name)
|
||||
dvs_id = az.dvs_id
|
||||
return nsx_db.get_nsx_switch_id_for_dvs(
|
||||
context.session, network_id, dvs_id)
|
||||
# Get the physical port group /wire id of the network id
|
||||
@ -2215,15 +2306,6 @@ def clear_gateway(nsxv_manager, context, router_id):
|
||||
return update_gateway(nsxv_manager, context, router_id, None)
|
||||
|
||||
|
||||
def update_external_interface(
|
||||
nsxv_manager, context, router_id, ext_net_id,
|
||||
ipaddr, netmask, secondary=None):
|
||||
with locking.LockManager.get_lock(str(router_id)):
|
||||
_update_external_interface(nsxv_manager, context, router_id,
|
||||
ext_net_id, ipaddr, netmask,
|
||||
secondary=secondary)
|
||||
|
||||
|
||||
def _check_ipnet_ip(ipnet, ip_address):
|
||||
"""Check one ip is valid ip from ipnet."""
|
||||
ip = netaddr.IPAddress(ip_address)
|
||||
@ -2234,73 +2316,6 @@ def _check_ipnet_ip(ipnet, ip_address):
|
||||
return False
|
||||
|
||||
|
||||
def _update_external_interface(
|
||||
nsxv_manager, context, router_id, ext_net_id,
|
||||
ipaddr, netmask, secondary=None):
|
||||
secondary = secondary or []
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
|
||||
# If no binding was found, no interface to update - exit
|
||||
if not binding:
|
||||
LOG.error(_LE('Edge binding not found for router %s'), router_id)
|
||||
return
|
||||
|
||||
net_bindings = nsxv_db.get_network_bindings(context.session, ext_net_id)
|
||||
if not net_bindings:
|
||||
vcns_network_id = nsxv_manager.external_network
|
||||
else:
|
||||
vcns_network_id = net_bindings[0].phy_uuid
|
||||
|
||||
# reorganize external vnic's address groups
|
||||
if netmask:
|
||||
address_groups = []
|
||||
addr_list = []
|
||||
for str_cidr in netmask:
|
||||
ip_net = netaddr.IPNetwork(str_cidr)
|
||||
address_group = {'primaryAddress': None,
|
||||
'subnetPrefixLength': str(ip_net.prefixlen)}
|
||||
if (ipaddr not in addr_list and
|
||||
_check_ipnet_ip(ip_net, ipaddr)):
|
||||
address_group['primaryAddress'] = ipaddr
|
||||
addr_list.append(ipaddr)
|
||||
for sec_ip in secondary:
|
||||
if (sec_ip not in addr_list and
|
||||
_check_ipnet_ip(ip_net, sec_ip)):
|
||||
if not address_group['primaryAddress']:
|
||||
address_group['primaryAddress'] = sec_ip
|
||||
else:
|
||||
if not address_group.get('secondaryAddresses'):
|
||||
address_group['secondaryAddresses'] = {
|
||||
'ipAddress': [sec_ip],
|
||||
'type': 'secondary_addresses'}
|
||||
else:
|
||||
address_group['secondaryAddresses'][
|
||||
'ipAddress'].append(sec_ip)
|
||||
addr_list.append(sec_ip)
|
||||
if address_group['primaryAddress']:
|
||||
address_groups.append(address_group)
|
||||
if ipaddr not in addr_list:
|
||||
LOG.error(_LE("primary address %s of ext vnic is not "
|
||||
"configured"), ipaddr)
|
||||
if secondary:
|
||||
missed_ip_sec = set(secondary) - set(addr_list)
|
||||
if missed_ip_sec:
|
||||
LOG.error(_LE("secondary address %s of ext vnic are not "
|
||||
"configured"), str(missed_ip_sec))
|
||||
nsxv_manager.update_interface(router_id, binding['edge_id'],
|
||||
vcns_const.EXTERNAL_VNIC_INDEX,
|
||||
vcns_network_id,
|
||||
address_groups=address_groups)
|
||||
|
||||
else:
|
||||
nsxv_manager.update_interface(router_id, binding['edge_id'],
|
||||
vcns_const.EXTERNAL_VNIC_INDEX,
|
||||
vcns_network_id,
|
||||
address=ipaddr,
|
||||
netmask=netmask,
|
||||
secondary=secondary)
|
||||
|
||||
|
||||
def update_internal_interface(nsxv_manager, context, router_id, int_net_id,
|
||||
address_groups, is_connected=True):
|
||||
with locking.LockManager.get_lock(str(router_id)):
|
||||
@ -2311,15 +2326,18 @@ def update_internal_interface(nsxv_manager, context, router_id, int_net_id,
|
||||
|
||||
def _update_internal_interface(nsxv_manager, context, router_id, int_net_id,
|
||||
address_groups, is_connected=True):
|
||||
# Get the pg/wire id of the network id
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, int_net_id)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': int_net_id,
|
||||
'net_moref': vcns_network_id})
|
||||
|
||||
# Get edge id
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
edge_id = binding['edge_id']
|
||||
|
||||
# Get the pg/wire id of the network id
|
||||
az_name = binding['availability_zone']
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, int_net_id, az_name)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': int_net_id,
|
||||
'net_moref': vcns_network_id})
|
||||
|
||||
edge_vnic_binding = nsxv_db.get_edge_vnic_binding(
|
||||
context.session, edge_id, int_net_id)
|
||||
# if edge_vnic_binding is None, then first select one available
|
||||
@ -2345,14 +2363,17 @@ def add_vdr_internal_interface(nsxv_manager, context, router_id,
|
||||
|
||||
def _add_vdr_internal_interface(nsxv_manager, context, router_id,
|
||||
int_net_id, address_groups, is_connected=True):
|
||||
# Get the pg/wire id of the network id
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, int_net_id)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': int_net_id,
|
||||
'net_moref': vcns_network_id})
|
||||
# Get edge id
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
edge_id = binding['edge_id']
|
||||
|
||||
# Get the pg/wire id of the network id
|
||||
az_name = binding['availability_zone']
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, int_net_id, az_name)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': int_net_id,
|
||||
'net_moref': vcns_network_id})
|
||||
|
||||
edge_vnic_binding = nsxv_db.get_edge_vnic_binding(
|
||||
context.session, edge_id, int_net_id)
|
||||
if not edge_vnic_binding:
|
||||
@ -2378,15 +2399,17 @@ def update_vdr_internal_interface(nsxv_manager, context, router_id, int_net_id,
|
||||
def _update_vdr_internal_interface(nsxv_manager, context, router_id,
|
||||
int_net_id, address_groups,
|
||||
is_connected=True):
|
||||
# Get edge id
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
edge_id = binding['edge_id']
|
||||
|
||||
# Get the pg/wire id of the network id
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, int_net_id)
|
||||
az_name = binding['availability_zone']
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, int_net_id, az_name)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': int_net_id,
|
||||
'net_moref': vcns_network_id})
|
||||
|
||||
# Get edge id
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
edge_id = binding['edge_id']
|
||||
edge_vnic_binding = nsxv_db.get_edge_vnic_binding(
|
||||
context.session, edge_id, int_net_id)
|
||||
nsxv_manager.update_vdr_internal_interface(
|
||||
@ -2402,12 +2425,6 @@ def delete_interface(nsxv_manager, context, router_id, network_id, dist=False):
|
||||
|
||||
def _delete_interface(nsxv_manager, context, router_id, network_id,
|
||||
dist=False):
|
||||
# Get the pg/wire id of the network id
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, network_id)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': network_id,
|
||||
'net_moref': vcns_network_id})
|
||||
|
||||
# Get edge id
|
||||
binding = nsxv_db.get_nsxv_router_binding(context.session, router_id)
|
||||
if not binding:
|
||||
@ -2416,6 +2433,14 @@ def _delete_interface(nsxv_manager, context, router_id, network_id,
|
||||
return
|
||||
|
||||
edge_id = binding['edge_id']
|
||||
|
||||
# Get the pg/wire id of the network id
|
||||
az_name = binding['availability_zone']
|
||||
vcns_network_id = _retrieve_nsx_switch_id(context, network_id, az_name)
|
||||
LOG.debug("Network id %(network_id)s corresponding ref is : "
|
||||
"%(net_moref)s", {'network_id': network_id,
|
||||
'net_moref': vcns_network_id})
|
||||
|
||||
edge_vnic_binding = nsxv_db.get_edge_vnic_binding(
|
||||
context.session, edge_id, network_id)
|
||||
if not edge_vnic_binding:
|
||||
|
@ -42,7 +42,6 @@ class VcnsDriver(edge_appliance_driver.EdgeApplianceDriver,
|
||||
self.insecure = cfg.CONF.nsxv.insecure
|
||||
self.datacenter_moid = cfg.CONF.nsxv.datacenter_moid
|
||||
self.deployment_container_id = cfg.CONF.nsxv.deployment_container_id
|
||||
self.external_network = cfg.CONF.nsxv.external_network
|
||||
self._pid = None
|
||||
self._task_manager = None
|
||||
self.vcns = vcns.Vcns(self.vcns_uri, self.vcns_user, self.vcns_passwd,
|
||||
|
@ -22,9 +22,11 @@ from neutron.db import models_v2
|
||||
from oslo_config import cfg
|
||||
|
||||
from vmware_nsx._i18n import _LE, _LI
|
||||
from vmware_nsx.common import config
|
||||
from vmware_nsx.common import locking
|
||||
from vmware_nsx.common import nsxv_constants
|
||||
from vmware_nsx.db import nsxv_db
|
||||
from vmware_nsx.plugins.nsx_v import availability_zones as nsx_az
|
||||
from vmware_nsx.plugins.nsx_v import md_proxy
|
||||
from vmware_nsx.plugins.nsx_v.vshield.common import constants as vcns_constants
|
||||
from vmware_nsx.plugins.nsx_v.vshield import nsxv_loadbalancer as nsxv_lb
|
||||
@ -42,26 +44,48 @@ nsxv = utils.get_nsxv_client()
|
||||
@admin_utils.output_header
|
||||
def nsx_redo_metadata_cfg(resource, event, trigger, **kwargs):
|
||||
edgeapi = utils.NeutronDbClient()
|
||||
net_list = nsxv_db.get_nsxv_internal_network(
|
||||
|
||||
config.register_nsxv_azs(cfg.CONF, cfg.CONF.nsxv.availability_zones)
|
||||
conf_az = nsx_az.ConfiguredAvailabilityZones()
|
||||
az_list = conf_az.list_availability_zones()
|
||||
for name in az_list:
|
||||
az = conf_az.get_availability_zone(name)
|
||||
if az.supports_metadata():
|
||||
nsx_redo_metadata_cfg_for_az(az, edgeapi)
|
||||
else:
|
||||
LOG.info(_LI("Skipping availability zone: %s - no metadata "
|
||||
"configuration"), az.name)
|
||||
|
||||
|
||||
def nsx_redo_metadata_cfg_for_az(az, edgeapi):
|
||||
LOG.info(_LI("Updating MetaData for availability zone: %s"), az.name)
|
||||
|
||||
# Get the list of internal networks for this AZ
|
||||
db_net = nsxv_db.get_nsxv_internal_network(
|
||||
edgeapi.context.session,
|
||||
vcns_constants.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
vcns_constants.InternalEdgePurposes.INTER_EDGE_PURPOSE,
|
||||
az.name)
|
||||
|
||||
internal_net = None
|
||||
internal_subnet = None
|
||||
if net_list:
|
||||
internal_net = net_list[0]['network_id']
|
||||
if db_net:
|
||||
internal_net = db_net['network_id']
|
||||
internal_subnet = edgeapi.context.session.query(
|
||||
models_v2.Subnet).filter_by(
|
||||
network_id=internal_net).first().get('id')
|
||||
|
||||
# Get the list of internal edges for this AZ
|
||||
edge_list = nsxv_db.get_nsxv_internal_edges_by_purpose(
|
||||
edgeapi.context.session,
|
||||
vcns_constants.InternalEdgePurposes.INTER_EDGE_PURPOSE)
|
||||
edge_az_list = [edge for edge in edge_list if
|
||||
nsxv_db.get_router_availability_zone(
|
||||
edgeapi.context.session, edge['router_id']) == az.name]
|
||||
|
||||
md_rtr_ids = [edge['router_id'] for edge in edge_list]
|
||||
md_rtr_ids = [edge['router_id'] for edge in edge_az_list]
|
||||
|
||||
edge_internal_ips = []
|
||||
for edge in edge_list:
|
||||
for edge in edge_az_list:
|
||||
edge_internal_port = edgeapi.context.session.query(
|
||||
models_v2.Port).filter_by(network_id=internal_net,
|
||||
device_id=edge['router_id']).first()
|
||||
@ -79,7 +103,8 @@ def nsx_redo_metadata_cfg(resource, event, trigger, **kwargs):
|
||||
|
||||
router_bindings = nsxv_db.get_nsxv_router_bindings(
|
||||
edgeapi.context.session,
|
||||
filters={'edge_type': [nsxv_constants.SERVICE_EDGE]})
|
||||
filters={'edge_type': [nsxv_constants.SERVICE_EDGE],
|
||||
'availability_zones': az.name})
|
||||
edge_ids = list(set([binding['edge_id'] for binding in router_bindings
|
||||
if (binding['router_id'] not in set(md_rtr_ids)
|
||||
and not binding['router_id'].startswith(
|
||||
|
@ -110,10 +110,11 @@ def nsx_recreate_router_edge(resource, event, trigger, **kwargs):
|
||||
# Go over all the relevant routers
|
||||
for router in routers:
|
||||
router_id = router['id']
|
||||
az_name = router['availability_zone']
|
||||
# clean up other objects related to this router
|
||||
if plugin.metadata_proxy_handler:
|
||||
plugin.metadata_proxy_handler.cleanup_router_edge(
|
||||
context, router_id)
|
||||
md_proxy = plugin.get_metadata_proxy_handler(az_name)
|
||||
md_proxy.cleanup_router_edge(context, router_id)
|
||||
|
||||
# attach the router to a new edge
|
||||
appliance_size = router.get(routersize.ROUTER_SIZE)
|
||||
|
@ -34,11 +34,23 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.group_name = 'az:%s' % self.az_name
|
||||
config.register_nsxv_azs(cfg.CONF, [self.az_name])
|
||||
cfg.CONF.set_override("ha_placement_random", True, group="nsxv")
|
||||
cfg.CONF.set_override("mgt_net_proxy_ips", ["2.2.2.2"], group="nsxv")
|
||||
cfg.CONF.set_override("dvs_id", "dvs-1", group="nsxv")
|
||||
|
||||
def _config_az(self, resource_pool_id="respool", datastore_id="datastore",
|
||||
edge_ha=True, ha_datastore_id="hastore",
|
||||
def _config_az(self,
|
||||
resource_pool_id="respool",
|
||||
datastore_id="datastore",
|
||||
edge_ha=True,
|
||||
ha_datastore_id="hastore",
|
||||
backup_edge_pool=DEF_AZ_POOL,
|
||||
ha_placement_random=False,
|
||||
backup_edge_pool=DEF_AZ_POOL):
|
||||
mgt_net_moid="portgroup-407",
|
||||
mgt_net_proxy_ips=["1.1.1.1"],
|
||||
mgt_net_proxy_netmask="255.255.255.0",
|
||||
mgt_net_default_gateway="2.2.2.2",
|
||||
external_network="network-17",
|
||||
vdn_scope_id="vdnscope-1",
|
||||
dvs_id="dvs-2"):
|
||||
cfg.CONF.set_override("resource_pool_id", resource_pool_id,
|
||||
group=self.group_name)
|
||||
cfg.CONF.set_override("datastore_id", datastore_id,
|
||||
@ -55,6 +67,29 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
if backup_edge_pool is not None:
|
||||
cfg.CONF.set_override("backup_edge_pool", backup_edge_pool,
|
||||
group=self.group_name)
|
||||
if mgt_net_moid is not None:
|
||||
cfg.CONF.set_override("mgt_net_moid", mgt_net_moid,
|
||||
group=self.group_name)
|
||||
if mgt_net_proxy_ips is not None:
|
||||
cfg.CONF.set_override("mgt_net_proxy_ips", mgt_net_proxy_ips,
|
||||
group=self.group_name)
|
||||
if mgt_net_proxy_netmask is not None:
|
||||
cfg.CONF.set_override("mgt_net_proxy_netmask",
|
||||
mgt_net_proxy_netmask,
|
||||
group=self.group_name)
|
||||
if mgt_net_default_gateway is not None:
|
||||
cfg.CONF.set_override("mgt_net_default_gateway",
|
||||
mgt_net_default_gateway,
|
||||
group=self.group_name)
|
||||
if external_network is not None:
|
||||
cfg.CONF.set_override("external_network", external_network,
|
||||
group=self.group_name)
|
||||
if vdn_scope_id is not None:
|
||||
cfg.CONF.set_override("vdn_scope_id", vdn_scope_id,
|
||||
group=self.group_name)
|
||||
if dvs_id is not None:
|
||||
cfg.CONF.set_override("dvs_id", dvs_id,
|
||||
group=self.group_name)
|
||||
|
||||
def test_simple_availability_zone(self):
|
||||
self._config_az()
|
||||
@ -62,10 +97,18 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual(self.az_name, az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertTrue(az.edge_ha)
|
||||
self.assertEqual("hastore", az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
self.assertFalse(az.ha_placement_random)
|
||||
self.assertEqual(DEF_AZ_POOL, az.backup_edge_pool)
|
||||
self.assertEqual("portgroup-407", az.mgt_net_moid)
|
||||
self.assertEqual(["1.1.1.1"], az.mgt_net_proxy_ips)
|
||||
self.assertEqual("255.255.255.0", az.mgt_net_proxy_netmask)
|
||||
self.assertEqual("2.2.2.2", az.mgt_net_default_gateway)
|
||||
self.assertEqual("network-17", az.external_network)
|
||||
self.assertEqual("vdnscope-1", az.vdn_scope_id)
|
||||
self.assertEqual("dvs-2", az.dvs_id)
|
||||
self.assertTrue(az.az_metadata_support)
|
||||
|
||||
def test_availability_zone_no_edge_ha(self):
|
||||
self._config_az(edge_ha=False)
|
||||
@ -73,9 +116,9 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual(self.az_name, az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(False, az.edge_ha)
|
||||
self.assertEqual(None, az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
self.assertFalse(az.edge_ha)
|
||||
self.assertIsNone(az.ha_datastore_id)
|
||||
self.assertFalse(az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_no_ha_datastore(self):
|
||||
self._config_az(ha_datastore_id=None)
|
||||
@ -83,9 +126,9 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual(self.az_name, az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertEqual(None, az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
self.assertTrue(az.edge_ha)
|
||||
self.assertIsNone(az.ha_datastore_id)
|
||||
self.assertFalse(az.ha_placement_random)
|
||||
|
||||
def test_missing_group_section(self):
|
||||
self.assertRaises(
|
||||
@ -113,9 +156,9 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual(self.az_name, az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(False, az.edge_ha)
|
||||
self.assertEqual(None, az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
self.assertFalse(az.edge_ha)
|
||||
self.assertIsNone(az.ha_datastore_id)
|
||||
self.assertFalse(az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_missing_edge_placement(self):
|
||||
self._config_az(ha_placement_random=None)
|
||||
@ -123,10 +166,10 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
self.assertEqual(self.az_name, az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertTrue(az.edge_ha)
|
||||
self.assertEqual("hastore", az.ha_datastore_id)
|
||||
# ha_placement_random should have the global value
|
||||
self.assertEqual(True, az.ha_placement_random)
|
||||
self.assertTrue(az.ha_placement_random)
|
||||
|
||||
def test_availability_zone_missing_backup_pool(self):
|
||||
self._config_az(backup_edge_pool=None)
|
||||
@ -135,6 +178,28 @@ class NsxvAvailabilityZonesTestCase(base.BaseTestCase):
|
||||
# Should use the global configuration instead
|
||||
self.assertEqual(DEF_GLOBAL_POOL, az.backup_edge_pool)
|
||||
|
||||
def test_availability_zone_missing_metadata(self):
|
||||
self._config_az(mgt_net_proxy_ips=None)
|
||||
az = nsx_az.ConfiguredAvailabilityZone(self.az_name)
|
||||
self.assertIsNone(az.mgt_net_moid)
|
||||
self.assertEqual([], az.mgt_net_proxy_ips)
|
||||
self.assertIsNone(az.mgt_net_proxy_netmask)
|
||||
self.assertIsNone(az.mgt_net_default_gateway)
|
||||
self.assertFalse(az.az_metadata_support)
|
||||
|
||||
def test_availability_zone_same_metadata(self):
|
||||
self._config_az(mgt_net_proxy_ips=["2.2.2.2"])
|
||||
self.assertRaises(
|
||||
nsx_exc.NsxInvalidConfiguration,
|
||||
nsx_az.ConfiguredAvailabilityZone,
|
||||
self.az_name)
|
||||
|
||||
self._config_az(mgt_net_proxy_ips=["2.2.2.2", "3.3.3.3"])
|
||||
self.assertRaises(
|
||||
nsx_exc.NsxInvalidConfiguration,
|
||||
nsx_az.ConfiguredAvailabilityZone,
|
||||
self.az_name)
|
||||
|
||||
|
||||
class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||
"""Test old way of configuring the availability zones
|
||||
@ -142,16 +207,31 @@ class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||
using a one-line configuration instead of different dynamic sections
|
||||
"""
|
||||
|
||||
def setUp(self):
|
||||
super(NsxvAvailabilityZonesOldTestCase, self).setUp()
|
||||
cfg.CONF.set_override("mgt_net_proxy_ips", ["2.2.2.2"], group="nsxv")
|
||||
cfg.CONF.set_override("dvs_id", "dvs-1", group="nsxv")
|
||||
|
||||
def test_simple_availability_zone(self):
|
||||
az = nsx_az.ConfiguredAvailabilityZone(
|
||||
"name:respool:datastore:true:hastore")
|
||||
self.assertEqual("name", az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertTrue(az.edge_ha)
|
||||
self.assertEqual("hastore", az.ha_datastore_id)
|
||||
self.assertEqual(False, az.ha_placement_random)
|
||||
self.assertFalse(az.ha_placement_random)
|
||||
self.assertEqual(DEF_GLOBAL_POOL, az.backup_edge_pool)
|
||||
# should get the global configuration (which is empty now)
|
||||
self.assertIsNone(az.external_network)
|
||||
self.assertIsNone(az.vdn_scope_id)
|
||||
self.assertEqual("dvs-1", az.dvs_id)
|
||||
# no metadata per az support
|
||||
self.assertFalse(az.az_metadata_support)
|
||||
self.assertIsNone(az.mgt_net_moid)
|
||||
self.assertEqual([], az.mgt_net_proxy_ips)
|
||||
self.assertIsNone(az.mgt_net_proxy_netmask)
|
||||
self.assertIsNone(az.mgt_net_default_gateway)
|
||||
|
||||
def test_availability_zone_without_ha_datastore(self):
|
||||
az = nsx_az.ConfiguredAvailabilityZone(
|
||||
@ -159,7 +239,7 @@ class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||
self.assertEqual("name", az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(True, az.edge_ha)
|
||||
self.assertTrue(az.edge_ha)
|
||||
self.assertIsNone(az.ha_datastore_id)
|
||||
|
||||
def test_availability_zone_without_edge_ha(self):
|
||||
@ -168,7 +248,7 @@ class NsxvAvailabilityZonesOldTestCase(base.BaseTestCase):
|
||||
self.assertEqual("name", az.name)
|
||||
self.assertEqual("respool", az.resource_pool)
|
||||
self.assertEqual("datastore", az.datastore_id)
|
||||
self.assertEqual(False, az.edge_ha)
|
||||
self.assertFalse(az.edge_ha)
|
||||
self.assertIsNone(az.ha_datastore_id)
|
||||
|
||||
def test_availability_fail_long_name(self):
|
||||
|
@ -176,6 +176,9 @@ class NsxVPluginV2TestCase(test_plugin.NeutronDbPluginV2TestCase):
|
||||
plugin_instance.real_get_edge = plugin_instance._get_edge_id_by_rtr_id
|
||||
plugin_instance._get_edge_id_by_rtr_id = mock.Mock()
|
||||
plugin_instance._get_edge_id_by_rtr_id.return_value = False
|
||||
plugin_instance._get_edge_id_and_az_by_rtr_id = mock.Mock()
|
||||
plugin_instance._get_edge_id_and_az_by_rtr_id.return_value = (
|
||||
False, False)
|
||||
plugin_instance.edge_manager.is_dhcp_opt_enabled = True
|
||||
# call init_complete manually. The event is not called in unit tests
|
||||
plugin_instance.init_complete(None, None, {})
|
||||
@ -505,26 +508,28 @@ class TestNetworksV2(test_plugin.TestNetworksV2, NsxVPluginV2TestCase):
|
||||
|
||||
def test_get_dvs_ids_for_multiple_dvs_vlan_network(self):
|
||||
p = directory.get_plugin()
|
||||
default_dvs = 'fake_dvs_id'
|
||||
# If no DVS-ID is provided as part of physical network, return
|
||||
# global DVS-ID configured in nsx.ini
|
||||
physical_network = constants.ATTR_NOT_SPECIFIED
|
||||
self.assertEqual(['fake_dvs_id'], p._get_dvs_ids(physical_network))
|
||||
self.assertEqual(['fake_dvs_id'], p._get_dvs_ids(
|
||||
physical_network, default_dvs))
|
||||
# If DVS-IDs are provided as part of physical network as a comma
|
||||
# separated string, return them as a list of DVS-IDs.
|
||||
physical_network = 'dvs-1,dvs-2, dvs-3'
|
||||
expected_dvs_ids = ['dvs-1', 'dvs-2', 'dvs-3']
|
||||
self.assertEqual(expected_dvs_ids,
|
||||
sorted(p._get_dvs_ids(physical_network)))
|
||||
sorted(p._get_dvs_ids(physical_network, default_dvs)))
|
||||
# Ignore extra commas ',' in the physical_network attribute.
|
||||
physical_network = ',,,dvs-1,dvs-2,, dvs-3,'
|
||||
expected_dvs_ids = ['dvs-1', 'dvs-2', 'dvs-3']
|
||||
self.assertEqual(expected_dvs_ids,
|
||||
sorted(p._get_dvs_ids(physical_network)))
|
||||
sorted(p._get_dvs_ids(physical_network, default_dvs)))
|
||||
# Ignore duplicate DVS-IDs in the physical_network attribute.
|
||||
physical_network = ',,,dvs-1,dvs-2,, dvs-2,'
|
||||
expected_dvs_ids = ['dvs-1', 'dvs-2']
|
||||
self.assertEqual(expected_dvs_ids,
|
||||
sorted(p._get_dvs_ids(physical_network)))
|
||||
sorted(p._get_dvs_ids(physical_network, default_dvs)))
|
||||
|
||||
def test_create_vxlan_with_tz_provider_network(self):
|
||||
name = 'provider_net_vxlan'
|
||||
@ -3311,6 +3316,9 @@ class NsxVTestSecurityGroup(ext_sg.TestSecurityGroups,
|
||||
plugin_instance = directory.get_plugin()
|
||||
plugin_instance._get_edge_id_by_rtr_id = mock.Mock()
|
||||
plugin_instance._get_edge_id_by_rtr_id.return_value = False
|
||||
plugin_instance._get_edge_id_and_az_by_rtr_id = mock.Mock()
|
||||
plugin_instance._get_edge_id_and_az_by_rtr_id.return_value = (
|
||||
False, False)
|
||||
|
||||
def test_list_ports_security_group(self):
|
||||
with self.network() as n:
|
||||
|
@ -249,7 +249,7 @@ class FakeVcns(object):
|
||||
response = {
|
||||
'label': 'vNic_1',
|
||||
'name': 'internal1',
|
||||
'address_groups': {'address_groups': []},
|
||||
'addressGroups': {'addressGroups': []},
|
||||
'mtu': 1500,
|
||||
'type': 'trunk',
|
||||
'subInterfaces': {'subInterfaces': []},
|
||||
|
Loading…
Reference in New Issue
Block a user