Change network type shared_vlan name to vlan
1. What is the problem shared_vlan's concept is to create a network spanning into multiple OpenStack with same vlan segment, but when create a network which only resides in one region and the network type is vlan, we have to specify the physical network type as shared_vlan, otherwise no other way to create a vlan network in local Neutron. 2. What is the solution to the problem Just use vlan as the physical network type, and use availability_zone_hints to limit where the network will reside. 3. What the features need to be implemented to the Tricircle No new features Change-Id: Ib3f110e2281eff2997752debda319da282c3e3ad
This commit is contained in:
parent
33e3a8d353
commit
2d6cae8097
@ -171,10 +171,10 @@ function start_central_neutron_server {
|
||||
iniset $NEUTRON_CONF.$server_index client top_region_name $CENTRAL_REGION_NAME
|
||||
|
||||
if [ "$Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS" != "" ]; then
|
||||
iniset $NEUTRON_CONF.$server_index tricircle type_drivers local,shared_vlan
|
||||
iniset $NEUTRON_CONF.$server_index tricircle tenant_network_types local,shared_vlan
|
||||
iniset $NEUTRON_CONF.$server_index tricircle type_drivers local,vlan
|
||||
iniset $NEUTRON_CONF.$server_index tricircle tenant_network_types local,vlan
|
||||
iniset $NEUTRON_CONF.$server_index tricircle network_vlan_ranges `echo $Q_ML2_PLUGIN_VLAN_TYPE_OPTIONS | awk -F= '{print $2}'`
|
||||
iniset $NEUTRON_CONF.$server_index tricircle bridge_network_type shared_vlan
|
||||
iniset $NEUTRON_CONF.$server_index tricircle bridge_network_type vlan
|
||||
iniset $NEUTRON_CONF.$server_index tricircle enable_api_gateway False
|
||||
fi
|
||||
|
||||
|
@ -144,16 +144,16 @@ configured in central Neutron's neutron.conf.
|
||||
- (String) core plugin central Neutron server uses, should be set to tricircle.network.central_plugin.TricirclePlugin
|
||||
* - **[tricircle]**
|
||||
-
|
||||
* - ``bridge_network_type`` = ``shared_vlan``
|
||||
- (String) Type of l3 bridge network, this type should be enabled in tenant_network_types and is not local type, for example, shared_vlan.
|
||||
* - ``bridge_network_type`` = ``vlan``
|
||||
- (String) Type of l3 bridge network, this type should be enabled in tenant_network_types and is not local type, for example, vlan.
|
||||
* - ``default_region_for_external_network`` = ``RegionOne``
|
||||
- (String) Default region where the external network belongs to, it must exist, for example, RegionOne.
|
||||
* - ``network_vlan_ranges`` = ``None``
|
||||
- (String) List of <physical_network>:<vlan_min>:<vlan_max> or <physical_network> specifying physical_network names usable for VLAN provider and tenant networks, as well as ranges of VLAN tags on each available for allocation to tenant networks, for example,bridge:2001:3000.
|
||||
* - ``tenant_network_types`` = ``local,shared_vlan``
|
||||
- (String) Ordered list of network_types to allocate as tenant networks. The default value "local" is useful for single pod connectivity. For example, local and shared_vlan.
|
||||
* - ``type_drivers`` = ``local,shared_vlan``
|
||||
- (String) List of network type driver entry points to be loaded from the tricircle.network.type_drivers namespace. For example, local and shared_vlan.
|
||||
* - ``tenant_network_types`` = ``local,vlan``
|
||||
- (String) Ordered list of network_types to allocate as tenant networks. The default value "local" is useful for single pod connectivity. For example, local and vlan.
|
||||
* - ``type_drivers`` = ``local,vlan``
|
||||
- (String) List of network type driver entry points to be loaded from the tricircle.network.type_drivers namespace. For example, local and vlan.
|
||||
|
||||
|
||||
|
||||
|
@ -167,10 +167,10 @@ Installation with Central Neutron Server
|
||||
[client] admin_tenant, "project name of admin account", demo
|
||||
[client] admin_user_domain_name, "user domain name of admin account", Default
|
||||
[client] admin_tenant_domain_name, "project name of admin account", Default
|
||||
[tricircle] type_drivers, "list of network type driver entry points to be loaded", "local,shared_vlan"
|
||||
[tricircle] tenant_network_types, "ordered list of network_types to allocate as tenant networks", "local,shared_vlan"
|
||||
[tricircle] type_drivers, "list of network type driver entry points to be loaded", "local,vlan"
|
||||
[tricircle] tenant_network_types, "ordered list of network_types to allocate as tenant networks", "local,vlan"
|
||||
[tricircle] network_vlan_ranges, "physical_network names and VLAN tags range usable of VLAN provider", "bridge:2001:3000"
|
||||
[tricircle] bridge_network_type, "l3 bridge network type which is enabled in tenant_network_types and is not local type", shared_vlan
|
||||
[tricircle] bridge_network_type, "l3 bridge network type which is enabled in tenant_network_types and is not local type", vlan
|
||||
[tricircle] enable_api_gateway, "whether the API gateway is enabled", False
|
||||
|
||||
.. note:: Change keystone_service_host to the address of Keystone service.
|
||||
|
@ -16,8 +16,8 @@ to say, local type network doesn't support cross-pod l2 networking.
|
||||
With multi-pod installation of the Tricircle, you can try out cross-pod l2
|
||||
networking and cross-pod l3 networking features.
|
||||
|
||||
As the first step to support cross-pod l2 networking, we have added shared VLAN
|
||||
network type to the Tricircle. When a shared VLAN type network created via the
|
||||
As the first step to support cross-pod l2 networking, we have added VLAN
|
||||
network type to the Tricircle. When a VLAN type network created via the
|
||||
central Neutron server is used to boot virtual machines in different pods, local
|
||||
Neutron server in each pod will create a VLAN type network with the same VLAN
|
||||
ID and physical network as the central network, so each pod should be configured
|
||||
@ -49,7 +49,7 @@ attaches a subnet to a router via the central Neutron server and the job is
|
||||
finished asynchronously.
|
||||
|
||||
If one of the network connected to the router is not local type, meaning that
|
||||
cross-pod l2 networking is supported in this network(like shared VLAN type), and
|
||||
cross-pod l2 networking is supported in this network(like VLAN type), and
|
||||
the l2 network can be stretched into current pod, packets sent to the virtual
|
||||
machine in this network will not pass through the "bridge" network. Instead,
|
||||
packets first go to router, then are directly forwarded to the target virtual
|
||||
@ -58,7 +58,7 @@ network's availability zone hint. If the l2 network is not able to be stretched
|
||||
into the current pod, the packets will still pass through the "bridge network".
|
||||
For example, let's say we have two pods, pod1 and pod2, and two availability
|
||||
zones, az1 and az2. Pod1 belongs to az1 and pod2 belongs to az2. If the
|
||||
availability zone hint of one shared VLAN type network is set to az1, this
|
||||
availability zone hint of one VLAN type network is set to az1, this
|
||||
network can not be stretched to pod2. So packets sent from pod2 to virtual
|
||||
machines in this network still need to pass through the "bridge network".
|
||||
|
||||
@ -298,7 +298,7 @@ How to play
|
||||
|
||||
curl -X POST http://127.0.0.1:20001/v2.0/networks -H "Content-Type: application/json" \
|
||||
-H "X-Auth-Token: $token" \
|
||||
-d '{"network": {"name": "ext-net", "admin_state_up": true, "router:external": true, "provider:network_type": "shared_vlan", "provider:physical_network": "extern", "availability_zone_hints": ["RegionTwo"]}}'
|
||||
-d '{"network": {"name": "ext-net", "admin_state_up": true, "router:external": true, "provider:network_type": "vlan", "provider:physical_network": "extern", "availability_zone_hints": ["RegionTwo"]}}'
|
||||
neutron --os-region-name=CentralRegion subnet-create --name ext-subnet --disable-dhcp ext-net 163.3.124.0/24
|
||||
|
||||
Pay attention that when creating external network, we need to pass
|
||||
|
@ -54,7 +54,9 @@ features:
|
||||
- |
|
||||
Note for Networking
|
||||
|
||||
* Only Local Network and Shared VLAN network supported. Shared
|
||||
* Only Local Network and VLAN network supported.
|
||||
Local Network means the network will only present in one region,
|
||||
it could be VxLAN or VLAN network.
|
||||
VLAN is the only L2 network type which supports cross
|
||||
Neutron L2 networking and the bridge network for L3 networking.
|
||||
* Pagination and sort are not supported at the same time for list
|
||||
|
@ -60,4 +60,4 @@ tempest.test_plugins =
|
||||
|
||||
tricircle.network.type_drivers =
|
||||
local = tricircle.network.drivers.type_local:LocalTypeDriver
|
||||
shared_vlan = tricircle.network.drivers.type_shared_vlan:SharedVLANTypeDriver
|
||||
vlan = tricircle.network.drivers.type_vlan:VLANTypeDriver
|
||||
|
@ -114,12 +114,12 @@ Proposed Change
|
||||
===============
|
||||
|
||||
Cross pod L2 networking can be divided into three categories,
|
||||
``Shared VLAN``, ``Shared VxLAN`` and ``Mixed VLAN/VxLAN``.
|
||||
``VLAN``, ``Shared VxLAN`` and ``Mixed VLAN/VxLAN``.
|
||||
|
||||
* Shared VLAN
|
||||
* VLAN
|
||||
|
||||
Network in each bottom OpenStack is VLAN type and has the same VLAN ID.
|
||||
If we want shared VLAN L2 networking to work in multi-site scenario, i.e.,
|
||||
If we want VLAN L2 networking to work in multi-site scenario, i.e.,
|
||||
Multiple OpenStack instances in multiple sites, physical gateway needs to
|
||||
be manually configured to make one VLAN networking be extended to other
|
||||
sites.
|
||||
@ -180,7 +180,7 @@ L2 cross pod networking, and it should be compatible with the
|
||||
the Tricircle plugin need to load type driver according to the configuration.
|
||||
The Tricircle can reuse the type driver of ML2 with update.
|
||||
|
||||
* Type driver to allocate VLAN segment id for shared VLAN L2 networking.
|
||||
* Type driver to allocate VLAN segment id for VLAN L2 networking.
|
||||
|
||||
* Type driver to allocate VxLAN segment id for shared VxLAN L2 networking.
|
||||
|
||||
@ -203,7 +203,7 @@ the bottom OpenStack instances.
|
||||
Nova API-GW needs to get the network type from Neutron API server in the
|
||||
Tricircle, and deal with the networking automation based on the network type:
|
||||
|
||||
* Shared VLAN
|
||||
* VLAN
|
||||
Nova API-GW creates network in bottom OpenStack instance in which the VM will
|
||||
run with the VLAN segment id, network name and type that are retrieved from
|
||||
the Neutron API server in the Tricircle.
|
||||
@ -309,9 +309,9 @@ If a user wants to create VM2 in AZ2 or ``POD2`` in AZ1, and connect it to
|
||||
network ``Net1`` in the Tricircle, it would be failed. Because the ``Net1`` is
|
||||
local_network type network and it is limited to present in ``POD1`` in AZ1 only.
|
||||
|
||||
**Shared VLAN Implementation**
|
||||
**VLAN Implementation**
|
||||
|
||||
For Shared VLAN, L2GW is not required. This is the most simplest cross pod
|
||||
For VLAN, L2GW is not required. This is the most simplest cross pod
|
||||
L2 networking for limited scenario. For example, with a small number of
|
||||
networks, all VLANs are extended through physical gateway to support cross
|
||||
site VLAN networking, or all pods under same core switch with same visible
|
||||
@ -319,8 +319,8 @@ VLAN ranges that supported by the core switch are connected by the core
|
||||
switch.
|
||||
|
||||
when a user creates network called ``Net1``, the Tricircle plugin checks the
|
||||
configuration. If ``tenant_network_type`` equals ``shared_vlan``, the
|
||||
Tricircle will invoke Shared VLAN type driver. Shared VLAN driver will
|
||||
configuration. If ``tenant_network_type`` equals ``vlan``, the
|
||||
Tricircle will invoke VLAN type driver. VLAN driver will
|
||||
create ``segment``, and assign ``network_type`` with VLAN, update
|
||||
``segment`` and ``network_type`` and ``physical_network`` with DB
|
||||
|
||||
@ -466,12 +466,12 @@ be updated too.
|
||||
L3 bridge network N-S (North-South):
|
||||
|
||||
* For each tenant, one cross pod N-S bridge network should be created for router
|
||||
N-S inter-connection. Just replace the current shared VLAN N-S bridge network
|
||||
N-S inter-connection. Just replace the current VLAN N-S bridge network
|
||||
to corresponding Shared VxLAN or Mixed VLAN/VxLAN.
|
||||
|
||||
L3 bridge network E-W (East-West):
|
||||
|
||||
* When attaching router interface happened, for Shared VLAN, it will keep
|
||||
* When attaching router interface happened, for VLAN, it will keep
|
||||
current process to establish E-W bridge network. For Shared VxLAN and Mixed
|
||||
VLAN/VxLAN, if a L2 network is able to expand to the current pod, then just
|
||||
expand the L2 network to the pod, all E-W traffic will go out from local L2
|
||||
|
@ -527,7 +527,7 @@ shared VxLAN type and are attached to the router(also this router can only be
|
||||
legacy mode), so packets between net1 and net2 are routed in the router of the
|
||||
local OpenStack cloud and then sent to the target. Extra routes will be cleared
|
||||
so no packets will go through the bridge network. This is the current
|
||||
implementation of the Tricircle to support shared VLAN network.
|
||||
implementation of the Tricircle to support VLAN network.
|
||||
|
||||
Recommended Layer-3 Networking Mode
|
||||
-----------------------------------
|
||||
|
@ -143,12 +143,11 @@ Network Type Adaption
|
||||
---------------------
|
||||
|
||||
Two network types are supported currently in central plugin, which are local
|
||||
and shared vlan type. Before creating network based on information retrieved
|
||||
and vlan type. Before creating network based on information retrieved
|
||||
from central Neutron server, local plugin needs to adapt network type. For
|
||||
local type, local plugin creates the network without specifying the network
|
||||
type, so the default tenant network type is used. For shared vlan type, local
|
||||
plugin changes the network type parameter from "shared_vlan" to "vlan", but
|
||||
keeps the segmentation id and physical network parameter.
|
||||
type, so the default tenant network type is used. For vlan type, local plugin
|
||||
keeps the network type, segmentation id and physical network parameter.
|
||||
|
||||
We plan to support another two network types later. They are shared_vxlan and
|
||||
mixed network type. For shared_vxlan type, local plugin changes the network
|
||||
|
@ -85,4 +85,4 @@ JT_NETWORK_UPDATE = 'update_network'
|
||||
|
||||
# network type
|
||||
NT_LOCAL = 'local'
|
||||
NT_SHARED_VLAN = 'shared_vlan'
|
||||
NT_VLAN = 'vlan'
|
||||
|
@ -192,6 +192,14 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
[cfg.CONF.tricircle.default_region_for_external_network]
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def _fill_provider_info(from_net, to_net):
|
||||
provider_attrs = ('provider:network_type', 'provider:segmentation_id',
|
||||
'provider:physical_network')
|
||||
for provider_attr in provider_attrs:
|
||||
if validators.is_attr_set(from_net.get(provider_attr)):
|
||||
to_net[provider_attr] = from_net[provider_attr]
|
||||
|
||||
def _create_bottom_external_network(self, context, net, top_id):
|
||||
t_ctx = t_context.get_context_from_neutron_context(context)
|
||||
# use the first pod
|
||||
@ -205,12 +213,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
external_net.EXTERNAL: True
|
||||
}
|
||||
}
|
||||
provider_attrs = ('provider:network_type', 'provider:segmentation_id',
|
||||
'provider:physical_network')
|
||||
for provider_attr in provider_attrs:
|
||||
if validators.is_attr_set(net.get(provider_attr)):
|
||||
body['network'][provider_attr] = net[provider_attr]
|
||||
|
||||
self._fill_provider_info(net, body['network'])
|
||||
self._prepare_bottom_element(
|
||||
t_ctx, net['tenant_id'], pod, {'id': top_id},
|
||||
t_constants.RT_NETWORK, body)
|
||||
@ -267,6 +270,7 @@ class TricirclePlugin(db_base_plugin_v2.NeutronDbPluginV2,
|
||||
# put inside a session so when bottom operations fails db can
|
||||
# rollback
|
||||
if is_external:
|
||||
self._fill_provider_info(res, net_data)
|
||||
self._create_bottom_external_network(
|
||||
context, net_data, res['id'])
|
||||
return res
|
||||
|
@ -28,9 +28,9 @@ from tricircle.common.i18n import _LE, _LI
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class SharedVLANTypeDriver(type_vlan.VlanTypeDriver):
|
||||
class VLANTypeDriver(type_vlan.VlanTypeDriver):
|
||||
def __init__(self):
|
||||
super(SharedVLANTypeDriver, self).__init__()
|
||||
super(VLANTypeDriver, self).__init__()
|
||||
|
||||
def _parse_network_vlan_ranges(self):
|
||||
try:
|
||||
@ -43,18 +43,18 @@ class SharedVLANTypeDriver(type_vlan.VlanTypeDriver):
|
||||
LOG.info(_LI('Network VLAN ranges: %s'), self.network_vlan_ranges)
|
||||
|
||||
def get_type(self):
|
||||
return constants.NT_SHARED_VLAN
|
||||
return constants.NT_VLAN
|
||||
|
||||
def reserve_provider_segment(self, context, segment):
|
||||
res = super(SharedVLANTypeDriver,
|
||||
res = super(VLANTypeDriver,
|
||||
self).reserve_provider_segment(context, segment)
|
||||
res[driver_api.NETWORK_TYPE] = constants.NT_SHARED_VLAN
|
||||
res[driver_api.NETWORK_TYPE] = constants.NT_VLAN
|
||||
return res
|
||||
|
||||
def allocate_tenant_segment(self, context):
|
||||
res = super(SharedVLANTypeDriver,
|
||||
res = super(VLANTypeDriver,
|
||||
self).allocate_tenant_segment(context)
|
||||
res[driver_api.NETWORK_TYPE] = constants.NT_SHARED_VLAN
|
||||
res[driver_api.NETWORK_TYPE] = constants.NT_VLAN
|
||||
return res
|
||||
|
||||
def get_mtu(self, physical):
|
@ -42,7 +42,7 @@ class NetworkHelper(object):
|
||||
|
||||
@staticmethod
|
||||
def _transfer_network_type(network_type):
|
||||
network_type_map = {t_constants.NT_SHARED_VLAN: TYPE_VLAN}
|
||||
network_type_map = {t_constants.NT_VLAN: TYPE_VLAN}
|
||||
return network_type_map.get(network_type, network_type)
|
||||
|
||||
def _get_client(self, region_name=None):
|
||||
@ -209,7 +209,7 @@ class NetworkHelper(object):
|
||||
}
|
||||
}
|
||||
network_type = network.get('provider:network_type')
|
||||
if network_type == t_constants.NT_SHARED_VLAN:
|
||||
if network_type == t_constants.NT_VLAN:
|
||||
body['network']['provider:network_type'] = 'vlan'
|
||||
body['network']['provider:physical_network'] = network[
|
||||
'provider:physical_network']
|
||||
|
@ -81,8 +81,6 @@ class TricirclePlugin(plugin.Ml2Plugin):
|
||||
for key in ['provider:network_type', 'provider:physical_network',
|
||||
'provider:segmentation_id']:
|
||||
network.pop(key, None)
|
||||
elif network_type == t_constants.NT_SHARED_VLAN:
|
||||
network['provider:network_type'] = 'vlan'
|
||||
|
||||
# remove az_hint from network
|
||||
network.pop('availability_zone_hints', None)
|
||||
|
@ -16,9 +16,7 @@
|
||||
from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
from neutron.extensions import external_net
|
||||
from neutron.plugins.ml2 import managers
|
||||
from neutron_lib.api import validators
|
||||
|
||||
from tricircle.common.i18n import _LE
|
||||
from tricircle.common.i18n import _LI
|
||||
@ -66,20 +64,7 @@ class TricircleTypeManager(managers.TypeManager):
|
||||
if network_type not in self.drivers:
|
||||
self.drivers[network_type] = ext
|
||||
|
||||
@staticmethod
|
||||
def _is_external_network(network):
|
||||
external = network.get(external_net.EXTERNAL)
|
||||
external_set = validators.is_attr_set(external)
|
||||
if not external_set or not external:
|
||||
return False
|
||||
else:
|
||||
return True
|
||||
|
||||
def create_network_segments(self, context, network, tenant_id):
|
||||
# NOTE(zhiyuan) before we figure out how to deal with external network
|
||||
# segment allocation, skip segment creation for external network
|
||||
if self._is_external_network(network):
|
||||
return
|
||||
segments = self._process_provider_create(network)
|
||||
session = context.session
|
||||
with session.begin(subtransactions=True):
|
||||
@ -93,16 +78,3 @@ class TricircleTypeManager(managers.TypeManager):
|
||||
else:
|
||||
segment = self._allocate_tenant_net_segment(context)
|
||||
self._add_network_segment(context, network_id, segment)
|
||||
|
||||
def extend_networks_dict_provider(self, context, networks):
|
||||
internal_networks = []
|
||||
for network in networks:
|
||||
# NOTE(zhiyuan) before we figure out how to deal with external
|
||||
# network segment allocation, skip external network since it does
|
||||
# not have segment information
|
||||
if not self._is_external_network(network):
|
||||
internal_networks.append(network)
|
||||
if internal_networks:
|
||||
super(TricircleTypeManager,
|
||||
self).extend_networks_dict_provider(context,
|
||||
internal_networks)
|
||||
|
@ -60,7 +60,7 @@ from tricircle.db import core
|
||||
from tricircle.db import models
|
||||
import tricircle.network.central_plugin as plugin
|
||||
from tricircle.network.drivers import type_local
|
||||
from tricircle.network.drivers import type_shared_vlan
|
||||
from tricircle.network.drivers import type_vlan
|
||||
from tricircle.network import helper
|
||||
from tricircle.network import managers
|
||||
from tricircle.tests.unit.network import test_security_groups
|
||||
@ -972,8 +972,8 @@ class FakeTypeManager(managers.TricircleTypeManager):
|
||||
def _register_types(self):
|
||||
local_driver = type_local.LocalTypeDriver()
|
||||
self.drivers[constants.NT_LOCAL] = FakeExtension(local_driver)
|
||||
vlan_driver = type_shared_vlan.SharedVLANTypeDriver()
|
||||
self.drivers[constants.NT_SHARED_VLAN] = FakeExtension(vlan_driver)
|
||||
vlan_driver = type_vlan.VLANTypeDriver()
|
||||
self.drivers[constants.NT_VLAN] = FakeExtension(vlan_driver)
|
||||
|
||||
def extend_network_dict_provider(self, cxt, net):
|
||||
target_net = None
|
||||
@ -1115,14 +1115,14 @@ class PluginTest(unittest.TestCase,
|
||||
phynet = 'bridge'
|
||||
vlan_min = 2000
|
||||
vlan_max = 2001
|
||||
cfg.CONF.set_override('type_drivers', ['local', 'shared_vlan'],
|
||||
cfg.CONF.set_override('type_drivers', ['local', 'vlan'],
|
||||
group='tricircle')
|
||||
cfg.CONF.set_override('tenant_network_types', ['local', 'shared_vlan'],
|
||||
cfg.CONF.set_override('tenant_network_types', ['local', 'vlan'],
|
||||
group='tricircle')
|
||||
cfg.CONF.set_override('network_vlan_ranges',
|
||||
['%s:%d:%d' % (phynet, vlan_min, vlan_max)],
|
||||
group='tricircle')
|
||||
cfg.CONF.set_override('bridge_network_type', 'shared_vlan',
|
||||
cfg.CONF.set_override('bridge_network_type', 'vlan',
|
||||
group='tricircle')
|
||||
cfg.CONF.set_override('default_region_for_external_network',
|
||||
'pod_1', group='tricircle')
|
||||
|
@ -230,7 +230,7 @@ class PluginTest(unittest.TestCase):
|
||||
t_net = {'id': network_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
'name': 'net1',
|
||||
'provider:network_type': constants.NT_SHARED_VLAN,
|
||||
'provider:network_type': constants.NT_VLAN,
|
||||
'subnets': [subnet_id]}
|
||||
t_subnet = {'id': subnet_id,
|
||||
'tenant_id': self.tenant_id,
|
||||
|
Loading…
Reference in New Issue
Block a user