Merge "Update network interface puppet resource gen to support dual-stack"

This commit is contained in:
Zuul 2024-04-17 15:29:33 +00:00 committed by Gerrit Code Review
commit a4ab746619
19 changed files with 3006 additions and 2533 deletions

View File

@ -15,7 +15,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2015-2021 Wind River Systems, Inc. # Copyright (c) 2015-2024 Wind River Systems, Inc.
# #
@ -63,15 +63,26 @@ SUBCLOUD_WRITABLE_ADDRPOOLS = ['system-controller-subnet',
# so we can't depend on the address pool having a static name. # so we can't depend on the address pool having a static name.
SUBCLOUD_WRITABLE_NETWORK_TYPES = ['admin'] SUBCLOUD_WRITABLE_NETWORK_TYPES = ['admin']
# Address pool of oam and system controller oam are allowed to be of # Address pools of oam and system controller oam are allowed to be of
# overlapped prefix in the subcloud. # overlapped prefix in the subcloud.
OAM_ADDRESS_POOL = 'oam' if constants.DUAL_STACK_COMPATIBILITY_MODE:
SYSTEM_CONTROLLER_OAM_ADDRESS_POOL = 'system-controller-oam-subnet' OAM_ADDRESS_POOL_OVERLAP_INDEX = {'oam': 'system-controller-oam-subnet',
'oam-ipv4': 'system-controller-oam-subnet-ipv4',
'oam-ipv6': 'system-controller-oam-subnet-ipv6'}
else:
OAM_ADDRESS_POOL_OVERLAP_INDEX = {'oam-ipv4': 'system-controller-oam-subnet-ipv4',
'oam-ipv6': 'system-controller-oam-subnet-ipv6'}
# Address pool for the management network in an AIO-SX installation # Address pool for the management network in an AIO-SX installation
# is allowed to be deleted/modified post install # is allowed to be deleted/modified post install
MANAGEMENT_ADDRESS_POOL = 'management' if constants.DUAL_STACK_COMPATIBILITY_MODE:
AIOSX_WRITABLE_ADDRPOOLS = [MANAGEMENT_ADDRESS_POOL] MANAGEMENT_ADDRESS_POOL_NAMES = {None: 'management',
constants.IPV4_FAMILY: 'management-ipv4',
constants.IPV6_FAMILY: 'management-ipv6'}
else:
MANAGEMENT_ADDRESS_POOL_NAMES = {constants.IPV4_FAMILY: 'management-ipv4',
constants.IPV6_FAMILY: 'management-ipv6'}
AIOSX_WRITABLE_ADDRPOOLS = MANAGEMENT_ADDRESS_POOL_NAMES.values()
class AddressPoolPatchType(types.JsonPatchType): class AddressPoolPatchType(types.JsonPatchType):
@ -324,8 +335,8 @@ class AddressPoolController(rest.RestController):
f"{addrpool['prefix']}"]) f"{addrpool['prefix']}"])
pools = pecan.request.dbapi.address_pools_get_all() pools = pecan.request.dbapi.address_pools_get_all()
for pool in pools: for pool in pools:
if pool.name == OAM_ADDRESS_POOL and \ if pool.name in OAM_ADDRESS_POOL_OVERLAP_INDEX and \
addrpool['name'] == SYSTEM_CONTROLLER_OAM_ADDRESS_POOL: addrpool['name'] == OAM_ADDRESS_POOL_OVERLAP_INDEX[pool.name]:
# we are ignoring overlap in this case as subcloud oam and # we are ignoring overlap in this case as subcloud oam and
# system-controller oam are sharable. # system-controller oam are sharable.
continue continue
@ -405,15 +416,15 @@ class AddressPoolController(rest.RestController):
any(network.type == constants.NETWORK_TYPE_MGMT any(network.type == constants.NETWORK_TYPE_MGMT
for network in networks): for network in networks):
if (new_name != MANAGEMENT_ADDRESS_POOL): if (new_name != addrpool.name):
msg = _("Cannot complete the action because the " msg = _("Cannot complete the action because the "
"address pool for mgmt network must be named as '{}'." "address pool for mgmt network must be named as '{}'."
.format(MANAGEMENT_ADDRESS_POOL)) .format(addrpool.name))
raise ValueError(msg) raise ValueError(msg)
def _check_aiosx_mgmt(self, addrpool): def _check_aiosx_mgmt(self, addrpool):
if (utils.get_system_mode() == constants.SYSTEM_MODE_SIMPLEX and if (utils.get_system_mode() == constants.SYSTEM_MODE_SIMPLEX and
addrpool['name'] == MANAGEMENT_ADDRESS_POOL): addrpool['name'] in MANAGEMENT_ADDRESS_POOL_NAMES.values()):
if (utils.get_distributed_cloud_role() != if (utils.get_distributed_cloud_role() !=
constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD): constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD):
if 'gateway_address' in addrpool and \ if 'gateway_address' in addrpool and \
@ -750,7 +761,7 @@ class AddressPoolController(rest.RestController):
# if proxy is being used, remove the old management network IPs # if proxy is being used, remove the old management network IPs
# from the no_proxy list # from the no_proxy list
if cutils.is_initial_config_complete() and \ if cutils.is_initial_config_complete() and \
addrpool.name == MANAGEMENT_ADDRESS_POOL: addrpool.name in MANAGEMENT_ADDRESS_POOL_NAMES.values():
self._remove_mgmt_ips_from_no_proxy_list(addresses) self._remove_mgmt_ips_from_no_proxy_list(addresses)
# Delete the address pool, which will also delete any associated # Delete the address pool, which will also delete any associated

View File

@ -181,9 +181,13 @@ class NetworkController(rest.RestController):
# the use of addrpool named 'management'. # the use of addrpool named 'management'.
if pool_uuid: if pool_uuid:
pool = pecan.request.dbapi.address_pool_get(pool_uuid) pool = pecan.request.dbapi.address_pool_get(pool_uuid)
if pool['name'] != "management": if constants.DUAL_STACK_COMPATIBILITY_MODE:
msg = _("Network of type {} must use the addrpool named '{}'." pool_name = address_pool.MANAGEMENT_ADDRESS_POOL_NAMES[None]
.format(networktype, address_pool.MANAGEMENT_ADDRESS_POOL)) else:
pool_name = address_pool.MANAGEMENT_ADDRESS_POOL_NAMES[pool.family]
if pool['name'] != pool_name:
msg = _("Network of type {} must use the addrpool named '{}' for {}."
.format(networktype, pool_name, constants.IP_FAMILIES[pool.family]))
raise wsme.exc.ClientSideError(msg) raise wsme.exc.ClientSideError(msg)
def _check_network_pool(self, pool): def _check_network_pool(self, pool):

View File

@ -2508,3 +2508,7 @@ LUKS_VAULT_TYPE_NAME = "luks_encrypted_vault"
MGMT_IPSEC_ENABLING = 'enabling' MGMT_IPSEC_ENABLING = 'enabling'
MGMT_IPSEC_ENABLED = 'enabled' MGMT_IPSEC_ENABLED = 'enabled'
MGMT_IPSEC_DISABLED = 'disabled' MGMT_IPSEC_DISABLED = 'disabled'
# If True, makes outputs compatible with single stack versions of ansible-playbooks and stx-puppet.
# Shall be removed when the other projects are updated.
DUAL_STACK_COMPATIBILITY_MODE = True

View File

@ -732,6 +732,10 @@ class AddressNotFound(NotFound):
message = _("Address %(address_uuid)s could not be found.") message = _("Address %(address_uuid)s could not be found.")
class AddressNotFoundById(NotFound):
message = _("Address %(address_id)s could not be found.")
class AddressNotFoundByAddress(NotFound): class AddressNotFoundByAddress(NotFound):
message = _("Address %(address)s could not be found.") message = _("Address %(address)s could not be found.")

View File

@ -5141,7 +5141,9 @@ class Connection(api.Connection):
def networks_get_by_pool(self, pool_id, limit=None, marker=None, def networks_get_by_pool(self, pool_id, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):
query = model_query(models.Networks) query = model_query(models.Networks)
query = query.filter_by(address_pool_id=pool_id) query = (query.join(models.NetworkAddressPools,
models.NetworkAddressPools.network_id == models.Networks.id))
query = query.filter(models.NetworkAddressPools.address_pool_id == pool_id)
return _paginate_query(models.Networks, limit, marker, return _paginate_query(models.Networks, limit, marker,
sort_key, sort_dir, query) sort_key, sort_dir, query)
@ -5384,6 +5386,16 @@ class Connection(api.Connection):
raise exception.AddressNotFound(address_uuid=address_uuid) raise exception.AddressNotFound(address_uuid=address_uuid)
return result return result
def _address_get_by_id(self, address_id):
query = model_query(models.Addresses)
query = (query.
filter(models.Addresses.id == address_id))
try:
result = query.one()
except NoResultFound:
raise exception.AddressNotFoundById(address_id=address_id)
return result
def _address_query(self, values): def _address_query(self, values):
query = model_query(models.Addresses) query = model_query(models.Addresses)
query = (query. query = (query.
@ -5412,6 +5424,10 @@ class Connection(api.Connection):
def address_get(self, address_uuid): def address_get(self, address_uuid):
return self._address_get(address_uuid) return self._address_get(address_uuid)
@db_objects.objectify(objects.address)
def address_get_by_id(self, address_id):
return self._address_get_by_id(address_id)
@db_objects.objectify(objects.address) @db_objects.objectify(objects.address)
def address_get_by_name(self, name, limit=None, marker=None, def address_get_by_name(self, name, limit=None, marker=None,
sort_key=None, sort_dir=None): sort_key=None, sort_dir=None):

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2023 Wind River Systems, Inc. # Copyright (c) 2023-2024 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -88,7 +88,7 @@ class AddressPoolTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
def _delete_management_pool(self): def _delete_management_pool(self):
current_pools = self.get_json(self.API_PREFIX) current_pools = self.get_json(self.API_PREFIX)
for addrpool in current_pools[self.RESULT_KEY]: for addrpool in current_pools[self.RESULT_KEY]:
if addrpool['name'] == 'management': if addrpool['name'].startswith('management'):
uuid = addrpool['uuid'] uuid = addrpool['uuid']
self.delete(self.get_single_url(uuid), self.delete(self.get_single_url(uuid),
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -178,12 +178,14 @@ class TestPostMixin(AddressPoolTestCase):
f"with {name_1} address pool.", f"with {name_1} address pool.",
response.json['error_message']) response.json['error_message'])
def _test_create_address_pool_pass_overlap_with_oam(self, network, def _test_create_address_pool_pass_overlap_with_oam(self, network, prefix):
prefix):
name = "system-controller-oam-subnet" oam_pool_name = self._format_pool_name("oam", self.oam_subnet)
sysctl_oam_pool_name = self._format_pool_name("system-controller-oam-subnet",
self.oam_subnet)
# First test with different name, which should fail # First test with different name, which should fail
name_1 = f"{name}_1" name_1 = f"{sysctl_oam_pool_name}_1"
ndict_1 = self.get_post_object(name_1, network, prefix) ndict_1 = self.get_post_object(name_1, network, prefix)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict_1, ndict_1,
@ -194,11 +196,11 @@ class TestPostMixin(AddressPoolTestCase):
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(response.status_code, http_client.CONFLICT) self.assertEqual(response.status_code, http_client.CONFLICT)
self.assertIn(f"Address pool {network}/{prefix} overlaps " self.assertIn(f"Address pool {network}/{prefix} overlaps "
f"with oam address pool.", f"with {oam_pool_name} address pool.",
response.json['error_message']) response.json['error_message'])
# Now check with the name: system-controller-oam-subnet # Now check with the name: system-controller-oam-subnet
ndict_2 = self.get_post_object(name, network, prefix) ndict_2 = self.get_post_object(sysctl_oam_pool_name, network, prefix)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict_2, ndict_2,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -422,7 +424,11 @@ class TestPostMixin(AddressPoolTestCase):
network = str(self.mgmt_subnet.network) network = str(self.mgmt_subnet.network)
prefix = self.mgmt_subnet.prefixlen prefix = self.mgmt_subnet.prefixlen
ndict = self.get_post_object('management', network, prefix) if constants.DUAL_STACK_COMPATIBILITY_MODE:
name = "management"
else:
name = self._format_pool_name("management", self.mgmt_subnet)
ndict = self.get_post_object(name, network, prefix)
ndict['gateway_address'] = str(self.mgmt_subnet[1]) ndict['gateway_address'] = str(self.mgmt_subnet[1])
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,

View File

@ -2,7 +2,7 @@
# -*- encoding: utf-8 -*- # -*- encoding: utf-8 -*-
# #
# #
# Copyright (c) 2013-2023 Wind River Systems, Inc. # Copyright (c) 2013-2024 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -556,11 +556,6 @@ class InterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
if key in second: if key in second:
self.assertEqual(first[key], second[key]) self.assertEqual(first[key], second[key])
def _find_network_by_type(self, networktype):
for network in self.networks:
if network['type'] == networktype:
return network
def _find_address_pool_by_uuid(self, pool_uuid): def _find_address_pool_by_uuid(self, pool_uuid):
for pool in self.address_pools: for pool in self.address_pools:
if pool['uuid'] == pool_uuid: if pool['uuid'] == pool_uuid:

View File

@ -82,7 +82,7 @@ class NetworkTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
return self._create_test_network( return self._create_test_network(
name=network_type, name=network_type,
network_type=network_type, network_type=network_type,
subnet=self.mgmt_subnet, subnets=self.mgmt_subnets,
) )
# Don't create default test networks # Don't create default test networks
@ -103,31 +103,31 @@ class NetworkTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
self._create_test_addresses( self._create_test_addresses(
hostnames, hostnames,
self.mgmt_subnet, self.mgmt_subnets,
constants.NETWORK_TYPE_MGMT) constants.NETWORK_TYPE_MGMT)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.oam_subnet, hostnames, self.oam_subnets,
constants.NETWORK_TYPE_OAM) constants.NETWORK_TYPE_OAM)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.cluster_host_subnet, hostnames, self.cluster_host_subnets,
constants.NETWORK_TYPE_CLUSTER_HOST) constants.NETWORK_TYPE_CLUSTER_HOST)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.storage_subnet, hostnames, self.storage_subnets,
constants.NETWORK_TYPE_STORAGE) constants.NETWORK_TYPE_STORAGE)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.admin_subnet, hostnames, self.admin_subnets,
constants.NETWORK_TYPE_ADMIN) constants.NETWORK_TYPE_ADMIN)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.system_controller_subnet, hostnames, self.system_controller_subnets,
constants.NETWORK_TYPE_SYSTEM_CONTROLLER) constants.NETWORK_TYPE_SYSTEM_CONTROLLER)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.system_controller_oam_subnet, hostnames, self.system_controller_oam_subnets,
constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM) constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM)
@ -245,9 +245,16 @@ class TestPostMixin(NetworkTestCase):
constants.NETWORK_TYPE_PXEBOOT, constants.NETWORK_TYPE_PXEBOOT,
self.pxeboot_subnet) self.pxeboot_subnet)
def _get_mgmt_addrpool_name(self):
if constants.DUAL_STACK_COMPATIBILITY_MODE:
return 'management'
if self.primary_address_family == constants.IPV6_FAMILY:
return 'management-ipv6'
return 'management-ipv4'
def test_create_success_management(self): def test_create_success_management(self):
self._test_create_network_success( self._test_create_network_success(
'management', self._get_mgmt_addrpool_name(),
constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_MGMT,
self.mgmt_subnet) self.mgmt_subnet)
@ -321,7 +328,7 @@ class TestPostMixin(NetworkTestCase):
def test_create_fail_duplicate_management(self): def test_create_fail_duplicate_management(self):
self._test_create_network_fail_duplicate( self._test_create_network_fail_duplicate(
'management', self._get_mgmt_addrpool_name(),
constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_MGMT,
self.mgmt_subnet) self.mgmt_subnet)

View File

@ -111,8 +111,6 @@ class NetworkAddrpoolTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
return network return network
def _setup_context(self): def _setup_context(self):
print("_setup_context")
self.host0 = self._create_test_host(personality=constants.CONTROLLER, unit=0, self.host0 = self._create_test_host(personality=constants.CONTROLLER, unit=0,
id=1, mgmt_ip="1.1.1.1") id=1, mgmt_ip="1.1.1.1")
self.c0_oam_if = dbutils.create_test_interface(ifname='enp0s3', forihostid=self.host0.id) self.c0_oam_if = dbutils.create_test_interface(ifname='enp0s3', forihostid=self.host0.id)
@ -151,7 +149,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# Test creation of object # Test creation of object
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['management'].uuid) self.address_pools['management-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -159,9 +157,12 @@ class TestPostMixin(NetworkAddrpoolTestCase):
self.assertEqual('application/json', response.content_type) self.assertEqual('application/json', response.content_type)
self.assertEqual(response.status_code, http_client.OK) self.assertEqual(response.status_code, http_client.OK)
# Check that an expected field matches. # Check that an expected field matches.
self.assertEqual(response.json['address_pool_name'], self.address_pools['management'].name) self.assertEqual(response.json['address_pool_name'],
self.assertEqual(response.json['address_pool_id'], self.address_pools['management'].id) self.address_pools['management-ipv4'].name)
self.assertEqual(response.json['address_pool_uuid'], self.address_pools['management'].uuid) self.assertEqual(response.json['address_pool_id'],
self.address_pools['management-ipv4'].id)
self.assertEqual(response.json['address_pool_uuid'],
self.address_pools['management-ipv4'].uuid)
self.assertEqual(response.json['network_name'], self.networks[net_type].name) self.assertEqual(response.json['network_name'], self.networks[net_type].name)
self.assertEqual(response.json['network_id'], self.networks[net_type].id) self.assertEqual(response.json['network_id'], self.networks[net_type].id)
self.assertEqual(response.json['network_uuid'], self.networks[net_type].uuid) self.assertEqual(response.json['network_uuid'], self.networks[net_type].uuid)
@ -169,9 +170,9 @@ class TestPostMixin(NetworkAddrpoolTestCase):
uuid = response.json['uuid'] uuid = response.json['uuid']
# Verify that the object was created and some basic attribute matches # Verify that the object was created and some basic attribute matches
response = self.get_json(self.get_single_url(uuid)) response = self.get_json(self.get_single_url(uuid))
self.assertEqual(response['address_pool_name'], self.address_pools['management'].name) self.assertEqual(response['address_pool_name'], self.address_pools['management-ipv4'].name)
self.assertEqual(response['address_pool_id'], self.address_pools['management'].id) self.assertEqual(response['address_pool_id'], self.address_pools['management-ipv4'].id)
self.assertEqual(response['address_pool_uuid'], self.address_pools['management'].uuid) self.assertEqual(response['address_pool_uuid'], self.address_pools['management-ipv4'].uuid)
self.assertEqual(response['network_name'], self.networks[net_type].name) self.assertEqual(response['network_name'], self.networks[net_type].name)
self.assertEqual(response['network_id'], self.networks[net_type].id) self.assertEqual(response['network_id'], self.networks[net_type].id)
self.assertEqual(response['network_uuid'], self.networks[net_type].uuid) self.assertEqual(response['network_uuid'], self.networks[net_type].uuid)
@ -195,7 +196,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary # add primary
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['management'].uuid) self.address_pools['management-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -252,7 +253,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary # add primary
net_type = constants.NETWORK_TYPE_OAM net_type = constants.NETWORK_TYPE_OAM
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['oam'].uuid) self.address_pools['oam-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -367,7 +368,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary # add primary
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['management'].uuid) self.address_pools['management-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -377,7 +378,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add secondary # add secondary
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['oam'].uuid) self.address_pools['oam-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS, headers=self.API_HEADERS,
@ -390,7 +391,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary # add primary
net_type = constants.NETWORK_TYPE_PXEBOOT net_type = constants.NETWORK_TYPE_PXEBOOT
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['pxeboot'].uuid) self.address_pools['pxeboot-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -413,7 +414,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary # add primary
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['management'].uuid) self.address_pools['management-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -445,7 +446,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
def test_error_create_network_addrpool_primary_duplicate(self): def test_error_create_network_addrpool_primary_duplicate(self):
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
ndict = self.get_post_object(self.networks[net_type].uuid, ndict = self.get_post_object(self.networks[net_type].uuid,
self.address_pools['management'].uuid) self.address_pools['management-ipv4'].uuid)
response = self.post_json(self.API_PREFIX, response = self.post_json(self.API_PREFIX,
ndict, ndict,
headers=self.API_HEADERS) headers=self.API_HEADERS)
@ -486,7 +487,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['management'].id, address_pool_id=self.address_pools['management-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -507,7 +508,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['management'].id, address_pool_id=self.address_pools['management-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -528,7 +529,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_MGMT net_type = constants.NETWORK_TYPE_MGMT
net_pool_1 = dbutils.create_test_network_addrpool( net_pool_1 = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['management'].id, address_pool_id=self.address_pools['management-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
net_pool_2 = dbutils.create_test_network_addrpool( net_pool_2 = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['management-ipv6'].id, address_pool_id=self.address_pools['management-ipv6'].id,
@ -550,7 +551,7 @@ class TestDelete(NetworkAddrpoolTestCase):
# check that pool_uuid is filled since it was the secondary pool # check that pool_uuid is filled since it was the secondary pool
response = self.get_json(self.get_single_network_url(self.networks[net_type].uuid)) response = self.get_json(self.get_single_network_url(self.networks[net_type].uuid))
self.assertEqual(response['pool_uuid'], self.address_pools['management'].uuid) self.assertEqual(response['pool_uuid'], self.address_pools['management-ipv4'].uuid)
self.assertEqual(response['type'], self.networks[net_type].type) self.assertEqual(response['type'], self.networks[net_type].type)
self.assertEqual(response['primary_pool_family'], self.assertEqual(response['primary_pool_family'],
self.networks[net_type].primary_pool_family) self.networks[net_type].primary_pool_family)
@ -568,7 +569,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_OAM net_type = constants.NETWORK_TYPE_OAM
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['oam'].id, address_pool_id=self.address_pools['oam-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -589,7 +590,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_PXEBOOT net_type = constants.NETWORK_TYPE_PXEBOOT
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['pxeboot'].id, address_pool_id=self.address_pools['pxeboot-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -610,7 +611,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_CLUSTER_HOST net_type = constants.NETWORK_TYPE_CLUSTER_HOST
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['cluster-host'].id, address_pool_id=self.address_pools['cluster-host-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -631,7 +632,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_CLUSTER_HOST net_type = constants.NETWORK_TYPE_CLUSTER_HOST
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['cluster-pod'].id, address_pool_id=self.address_pools['cluster-pod-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -652,7 +653,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_CLUSTER_SERVICE net_type = constants.NETWORK_TYPE_CLUSTER_SERVICE
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['cluster-service'].id, address_pool_id=self.address_pools['cluster-service-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),
@ -673,7 +674,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_STORAGE net_type = constants.NETWORK_TYPE_STORAGE
net_pool = dbutils.create_test_network_addrpool( net_pool = dbutils.create_test_network_addrpool(
address_pool_id=self.address_pools['storage'].id, address_pool_id=self.address_pools['storage-ipv4'].id,
network_id=self.networks[net_type].id) network_id=self.networks[net_type].id)
response = self.delete(self.get_single_url(net_pool.uuid), response = self.delete(self.get_single_url(net_pool.uuid),

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2020 Wind River Systems, Inc. # Copyright (c) 2020-2024 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -204,6 +204,15 @@ class TestPatchMixin(OAMNetworkTestCase):
self._test_patch_success(patch_obj) self._test_patch_success(patch_obj)
def test_patch_incomplete(self): def test_patch_incomplete(self):
fields = {'floating_address_id': None, 'controller0_address_id': None,
'controller1_address_id': None, 'gateway_address_id': None}
network = self._find_network_by_type(constants.NETWORK_TYPE_OAM)
addrpools = self._find_network_address_pools(network.id)
for addrpool in addrpools:
addresses = self.dbapi.addresses_get_by_pool(addrpool.id)
for address in addresses:
self.dbapi.address_update(address.uuid, {'address_pool_id': None})
self.dbapi.address_pool_update(addrpool.uuid, fields)
oam_floating_ip = self.oam_subnet[2] + 100 oam_floating_ip = self.oam_subnet[2] + 100
patch_obj = { patch_obj = {
'oam_floating_ip': str(oam_floating_ip), 'oam_floating_ip': str(oam_floating_ip),

View File

@ -17,7 +17,7 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
# #
# Copyright (c) 2013-2023 Wind River Systems, Inc. # Copyright (c) 2013-2024 Wind River Systems, Inc.
# #
"""Test class for Sysinv ManagerService.""" """Test class for Sysinv ManagerService."""
@ -5910,13 +5910,15 @@ class ManagerTestCaseInternal(base.BaseHostTestCase):
net_mgmt = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_MGMT) net_mgmt = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_MGMT)
pool_mgmt6 = self.dbapi.address_pool_query({"name": "management-ipv6"}) pool_mgmt6 = self.dbapi.address_pool_query({"name": "management-ipv6"})
pool_mgmt4 = self.dbapi.address_pool_query({"name": "management"}) pool_mgmt4 = self.dbapi.address_pool_query({"name": "management-ipv4"})
dbutils.create_test_network_addrpool(address_pool_id=pool_mgmt6.id, network_id=net_mgmt.id) dbutils.create_test_network_addrpool(address_pool_id=pool_mgmt6.id,
network_id=net_mgmt.id)
net_clhost = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_CLUSTER_HOST) net_clhost = self.dbapi.network_get_by_type(constants.NETWORK_TYPE_CLUSTER_HOST)
pool_clhost6 = self.dbapi.address_pool_query({"name": "cluster-host-ipv6"}) pool_clhost6 = self.dbapi.address_pool_query({"name": "cluster-host-ipv6"})
pool_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host"}) pool_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host-ipv4"})
dbutils.create_test_network_addrpool(address_pool_id=pool_clhost6.id, network_id=net_clhost.id) dbutils.create_test_network_addrpool(address_pool_id=pool_clhost6.id,
network_id=net_clhost.id)
worker_name = 'newhost' worker_name = 'newhost'
ihost['mgmt_mac'] = '00:11:22:33:44:55' ihost['mgmt_mac'] = '00:11:22:33:44:55'
@ -5972,8 +5974,8 @@ class ManagerTestCaseInternal(base.BaseHostTestCase):
self.create_ipv6_pools() self.create_ipv6_pools()
pool_mgmt4 = self.dbapi.address_pool_query({"name": "management"}) pool_mgmt4 = self.dbapi.address_pool_query({"name": "management-ipv4"})
pool_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host"}) pool_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host-ipv4"})
net_pools = self.dbapi.network_addrpool_get_all() net_pools = self.dbapi.network_addrpool_get_all()
for net_pool in net_pools: for net_pool in net_pools:
self.dbapi.network_addrpool_destroy(net_pool.uuid) self.dbapi.network_addrpool_destroy(net_pool.uuid)

View File

@ -39,6 +39,33 @@ from sysinv.tests import base
from sysinv.tests.db import utils as dbutils from sysinv.tests.db import utils as dbutils
PXEBOOT_SUBNET = netaddr.IPNetwork('192.168.202.0/24')
MGMT_SUBNET_IPV4 = netaddr.IPNetwork('192.168.204.0/24')
OAM_SUBNET_IPV4 = netaddr.IPNetwork('10.10.10.0/24')
CLUSTER_HOST_SUBNET_IPV4 = netaddr.IPNetwork('192.168.206.0/24')
CLUSTER_POD_SUBNET_IPV4 = netaddr.IPNetwork('172.16.0.0/16')
CLUSTER_SERVICE_SUBNET_IPV4 = netaddr.IPNetwork('10.96.0.0/12')
MULTICAST_SUBNET_IPV4 = netaddr.IPNetwork('239.1.1.0/28')
STORAGE_SUBNET_IPV4 = netaddr.IPNetwork('10.10.20.0/24')
ADMIN_SUBNET_IPV4 = netaddr.IPNetwork('10.10.30.0/24')
SYSTEM_CONTROLLER_SUBNET_IPV4 = netaddr.IPNetwork('192.168.104.0/24')
SYSTEM_CONTROLLER_OAM_SUBNET_IPV4 = netaddr.IPNetwork('10.10.50.0/24')
NAMESERVERS_IPV4 = ['8.8.8.8', '8.8.4.4']
MGMT_SUBNET_IPV6 = netaddr.IPNetwork('fd01::/64')
OAM_SUBNET_IPV6 = netaddr.IPNetwork('fd00::/64')
CLUSTER_HOST_SUBNET_IPV6 = netaddr.IPNetwork('fd02::/64')
CLUSTER_POD_SUBNET_IPV6 = netaddr.IPNetwork('fd03::/64')
CLUSTER_SERVICE_SUBNET_IPV6 = netaddr.IPNetwork('fd04::/112')
MULTICAST_SUBNET_IPV6 = netaddr.IPNetwork('ff08::1:1:0/124')
STORAGE_SUBNET_IPV6 = netaddr.IPNetwork('fd05::/64')
ADMIN_SUBNET_IPV6 = netaddr.IPNetwork('fd09::/64')
SYSTEM_CONTROLLER_SUBNET_IPV6 = netaddr.IPNetwork('fd07::/64')
SYSTEM_CONTROLLER_OAM_SUBNET_IPV6 = netaddr.IPNetwork('fd06::/64')
NAMESERVERS_IPV6 = ['2001:4860:4860::8888', '2001:4860:4860::8844']
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class DbTestCase(base.TestCase): class DbTestCase(base.TestCase):
@ -49,19 +76,34 @@ class DbTestCase(base.TestCase):
class BaseIPv4Mixin(object): class BaseIPv4Mixin(object):
pxeboot_subnet = netaddr.IPNetwork('192.168.202.0/24') primary_address_family = constants.IPV4_FAMILY
mgmt_subnet = netaddr.IPNetwork('192.168.204.0/24') secondary_address_family = None
oam_subnet = netaddr.IPNetwork('10.10.10.0/24')
cluster_host_subnet = netaddr.IPNetwork('192.168.206.0/24')
cluster_pod_subnet = netaddr.IPNetwork('172.16.0.0/16')
cluster_service_subnet = netaddr.IPNetwork('10.96.0.0/12')
multicast_subnet = netaddr.IPNetwork('239.1.1.0/28')
storage_subnet = netaddr.IPNetwork('10.10.20.0/24')
admin_subnet = netaddr.IPNetwork('10.10.30.0/24')
system_controller_subnet = netaddr.IPNetwork('192.168.104.0/24')
system_controller_oam_subnet = netaddr.IPNetwork('10.10.50.0/24')
nameservers = ['8.8.8.8', '8.8.4.4'] pxeboot_subnet = PXEBOOT_SUBNET
mgmt_subnet = MGMT_SUBNET_IPV4
oam_subnet = OAM_SUBNET_IPV4
cluster_host_subnet = CLUSTER_HOST_SUBNET_IPV4
cluster_pod_subnet = CLUSTER_POD_SUBNET_IPV4
cluster_service_subnet = CLUSTER_SERVICE_SUBNET_IPV4
multicast_subnet = MULTICAST_SUBNET_IPV4
storage_subnet = STORAGE_SUBNET_IPV4
admin_subnet = ADMIN_SUBNET_IPV4
system_controller_subnet = SYSTEM_CONTROLLER_SUBNET_IPV4
system_controller_oam_subnet = SYSTEM_CONTROLLER_OAM_SUBNET_IPV4
pxeboot_subnets = [PXEBOOT_SUBNET]
mgmt_subnets = [MGMT_SUBNET_IPV4]
oam_subnets = [OAM_SUBNET_IPV4]
cluster_host_subnets = [CLUSTER_HOST_SUBNET_IPV4]
cluster_pod_subnets = [CLUSTER_POD_SUBNET_IPV4]
cluster_service_subnets = [CLUSTER_SERVICE_SUBNET_IPV4]
multicast_subnets = [MULTICAST_SUBNET_IPV4]
storage_subnets = [STORAGE_SUBNET_IPV4]
admin_subnets = [ADMIN_SUBNET_IPV4]
system_controller_subnets = [SYSTEM_CONTROLLER_SUBNET_IPV4]
system_controller_oam_subnets = [SYSTEM_CONTROLLER_OAM_SUBNET_IPV4]
nameservers = NAMESERVERS_IPV4
# Used to test changing oam from ipv4 to ipv6 # Used to test changing oam from ipv4 to ipv6
change_family_oam_subnet = netaddr.IPNetwork('fd00::/64') change_family_oam_subnet = netaddr.IPNetwork('fd00::/64')
@ -69,24 +111,77 @@ class BaseIPv4Mixin(object):
class BaseIPv6Mixin(object): class BaseIPv6Mixin(object):
pxeboot_subnet = netaddr.IPNetwork('192.168.202.0/24') primary_address_family = constants.IPV6_FAMILY
mgmt_subnet = netaddr.IPNetwork('fd01::/64') secondary_address_family = None
oam_subnet = netaddr.IPNetwork('fd00::/64')
cluster_host_subnet = netaddr.IPNetwork('fd02::/64')
cluster_pod_subnet = netaddr.IPNetwork('fd03::/64')
cluster_service_subnet = netaddr.IPNetwork('fd04::/112')
multicast_subnet = netaddr.IPNetwork('ff08::1:1:0/124')
storage_subnet = netaddr.IPNetwork('fd05::/64')
admin_subnet = netaddr.IPNetwork('fd09::/64')
system_controller_subnet = netaddr.IPNetwork('fd07::/64')
system_controller_oam_subnet = netaddr.IPNetwork('fd06::/64')
nameservers = ['2001:4860:4860::8888', '2001:4860:4860::8844'] pxeboot_subnet = PXEBOOT_SUBNET
mgmt_subnet = MGMT_SUBNET_IPV6
oam_subnet = OAM_SUBNET_IPV6
cluster_host_subnet = CLUSTER_HOST_SUBNET_IPV6
cluster_pod_subnet = CLUSTER_POD_SUBNET_IPV6
cluster_service_subnet = CLUSTER_SERVICE_SUBNET_IPV6
multicast_subnet = MULTICAST_SUBNET_IPV6
storage_subnet = STORAGE_SUBNET_IPV6
admin_subnet = ADMIN_SUBNET_IPV6
system_controller_subnet = SYSTEM_CONTROLLER_SUBNET_IPV6
system_controller_oam_subnet = SYSTEM_CONTROLLER_OAM_SUBNET_IPV6
pxeboot_subnets = [PXEBOOT_SUBNET]
mgmt_subnets = [MGMT_SUBNET_IPV6]
oam_subnets = [OAM_SUBNET_IPV6]
cluster_host_subnets = [CLUSTER_HOST_SUBNET_IPV6]
cluster_pod_subnets = [CLUSTER_POD_SUBNET_IPV6]
cluster_service_subnets = [CLUSTER_SERVICE_SUBNET_IPV6]
multicast_subnets = [MULTICAST_SUBNET_IPV6]
storage_subnets = [STORAGE_SUBNET_IPV6]
admin_subnets = [ADMIN_SUBNET_IPV6]
system_controller_subnets = [SYSTEM_CONTROLLER_SUBNET_IPV6]
system_controller_oam_subnets = [SYSTEM_CONTROLLER_OAM_SUBNET_IPV6]
nameservers = NAMESERVERS_IPV6
# Used to test changing oam from ipv6 to ipv4 # Used to test changing oam from ipv6 to ipv4
change_family_oam_subnet = netaddr.IPNetwork('10.10.10.0/24') change_family_oam_subnet = netaddr.IPNetwork('10.10.10.0/24')
class BaseDualStackPrimaryIPv4Mixin(BaseIPv4Mixin):
secondary_address_family = constants.IPV6_FAMILY
mgmt_subnets = [MGMT_SUBNET_IPV4, MGMT_SUBNET_IPV6]
oam_subnets = [OAM_SUBNET_IPV4, OAM_SUBNET_IPV6]
cluster_host_subnets = [CLUSTER_HOST_SUBNET_IPV4, CLUSTER_HOST_SUBNET_IPV6]
cluster_pod_subnets = [CLUSTER_POD_SUBNET_IPV4, CLUSTER_POD_SUBNET_IPV6]
cluster_service_subnets = [CLUSTER_SERVICE_SUBNET_IPV4, CLUSTER_SERVICE_SUBNET_IPV6]
multicast_subnets = [MULTICAST_SUBNET_IPV4, MULTICAST_SUBNET_IPV6]
storage_subnets = [STORAGE_SUBNET_IPV4, STORAGE_SUBNET_IPV6]
admin_subnets = [ADMIN_SUBNET_IPV4, ADMIN_SUBNET_IPV6]
system_controller_subnets = [SYSTEM_CONTROLLER_SUBNET_IPV4, SYSTEM_CONTROLLER_SUBNET_IPV6]
system_controller_oam_subnets = [SYSTEM_CONTROLLER_OAM_SUBNET_IPV4,
SYSTEM_CONTROLLER_OAM_SUBNET_IPV6]
nameservers = NAMESERVERS_IPV4 + NAMESERVERS_IPV6
class BaseDualStackPrimaryIPv6Mixin(BaseIPv6Mixin):
secondary_address_family = constants.IPV4_FAMILY
mgmt_subnets = [MGMT_SUBNET_IPV6, MGMT_SUBNET_IPV4]
oam_subnets = [OAM_SUBNET_IPV6, OAM_SUBNET_IPV4]
cluster_host_subnets = [CLUSTER_HOST_SUBNET_IPV6, CLUSTER_HOST_SUBNET_IPV4]
cluster_pod_subnets = [CLUSTER_POD_SUBNET_IPV6, CLUSTER_POD_SUBNET_IPV4]
cluster_service_subnets = [CLUSTER_SERVICE_SUBNET_IPV6, CLUSTER_SERVICE_SUBNET_IPV4]
multicast_subnets = [MULTICAST_SUBNET_IPV6, MULTICAST_SUBNET_IPV4]
storage_subnets = [STORAGE_SUBNET_IPV6, STORAGE_SUBNET_IPV4]
admin_subnets = [ADMIN_SUBNET_IPV6, ADMIN_SUBNET_IPV4]
system_controller_subnets = [SYSTEM_CONTROLLER_SUBNET_IPV6, SYSTEM_CONTROLLER_SUBNET_IPV4]
system_controller_oam_subnets = [SYSTEM_CONTROLLER_OAM_SUBNET_IPV6,
SYSTEM_CONTROLLER_OAM_SUBNET_IPV4]
nameservers = NAMESERVERS_IPV6 + NAMESERVERS_IPV4
class BaseCephStorageBackendMixin(object): class BaseCephStorageBackendMixin(object):
def setUp(self): def setUp(self):
@ -135,7 +230,10 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
super(BaseSystemTestCase, self).setUp() super(BaseSystemTestCase, self).setUp()
self.hosts = [] self.hosts = []
self.address_pools = [] self.address_pools = []
self.networks = [] self.networks_by_type = {}
self.networks_by_id = {}
self.address_pools_by_network_id = {}
self.addresses_by_id = {}
self.network_addrpools = [] self.network_addrpools = []
self.datanetworks = [] self.datanetworks = []
self._create_test_common() self._create_test_common()
@ -152,7 +250,9 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self.ptp = None self.ptp = None
self.hosts = [] self.hosts = []
self.address_pools = [] self.address_pools = []
self.networks = [] self.networks_by_type = {}
self.networks_by_id = {}
self.address_pools_by_network_id = {}
self.network_addrpools = [] self.network_addrpools = []
self.datanetworks = [] self.datanetworks = []
self.oam = None self.oam = None
@ -208,27 +308,50 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self.ptp = dbutils.create_test_ptp( self.ptp = dbutils.create_test_ptp(
system_id=self.system.id) system_id=self.system.id)
def _create_test_network(self, name, network_type, subnet, ranges=None): def _format_pool_name(self, network_name, subnet):
address_pool_id = self._create_test_address_pool(name, subnet, ranges).id if subnet.version == constants.IPV6_FAMILY:
family = 'ipv6'
else:
family = 'ipv4'
return network_name + '-' + family
primary_pool_family = "" def _create_test_network(self, name, network_type, subnets, link_addresses=False):
if not isinstance(subnet, netaddr.IPNetwork):
subnet = netaddr.IPNetwork(subnet)
primary_pool_family = constants.IP_FAMILIES[subnet.version] address_pools = []
for subnet in subnets:
pool_name = self._format_pool_name(name, subnet)
address_pool = self._create_test_address_pool(
pool_name, subnet, link_addresses=link_addresses)
address_pools.append(address_pool)
primary_pool_family = constants.IP_FAMILIES[subnets[0].version]
network = dbutils.create_test_network( network = dbutils.create_test_network(
type=network_type, type=network_type,
address_pool_id=address_pool_id, address_pool_id=address_pools[0].id,
primary_pool_family=primary_pool_family) primary_pool_family=primary_pool_family)
self.networks.append(network) self._add_network_to_index(network)
for address_pool in address_pools:
network_addrpool = dbutils.create_test_network_addrpool(
address_pool_id=address_pool.id, network_id=network.id)
self.network_addrpools.append(network_addrpool)
self._add_address_pool_to_index(address_pool, network)
network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=address_pool_id,
network_id=network.id)
self.network_addrpools.append(network_addrpool)
return network return network
def _add_network_to_index(self, network):
self.networks_by_type[network.type] = network
self.networks_by_id[network.id] = network
def _add_address_pool_to_index(self, addrpool, network):
pools = self.address_pools_by_network_id.get(network.id, None)
if not pools:
pools = []
self.address_pools_by_network_id[network.id] = pools
pools.append(addrpool)
def _create_test_route(self, interface, gateway, family=4, network='10.10.10.0', prefix=24): def _create_test_route(self, interface, gateway, family=4, network='10.10.10.0', prefix=24):
route = dbutils.create_test_route( route = dbutils.create_test_route(
interface_id=interface.id, interface_id=interface.id,
@ -245,16 +368,20 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self.datanetworks.append(datanetwork) self.datanetworks.append(datanetwork)
return datanetwork return datanetwork
def _create_test_address_pool(self, name, subnet, ranges=None, append=True): def _create_test_address_pool(self, name, subnet, ranges=None, append=True,
link_addresses=False):
if not ranges: if not ranges:
ranges = [(str(subnet[2]), str(subnet[-2]))] ranges = [(str(subnet[2]), str(subnet[-2]))]
base_address = netaddr.IPAddress(subnet[1])
gateway_address = None
floating_address = None floating_address = None
controller0_address = None controller0_address = None
controller1_address = None controller1_address = None
if name in ["pxeboot", "management", "oam", "cluster-host", "storage", "admin"]: if link_addresses:
floating_address = netaddr.IPAddress(ranges[0][0]) gateway_address = base_address
controller0_address = floating_address + 1 floating_address = base_address + 1
controller1_address = floating_address + 2 controller0_address = base_address + 2
controller1_address = base_address + 3
pool = dbutils.create_test_address_pool( pool = dbutils.create_test_address_pool(
name=name, name=name,
@ -262,6 +389,7 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
family=subnet.version, family=subnet.version,
prefix=subnet.prefixlen, prefix=subnet.prefixlen,
ranges=ranges, ranges=ranges,
gateway_address=str(gateway_address),
floating_address=str(floating_address), floating_address=str(floating_address),
controller0_address=str(controller0_address), controller0_address=str(controller0_address),
controller1_address=str(controller1_address)) controller1_address=str(controller1_address))
@ -273,43 +401,49 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self._create_test_network('pxeboot', self._create_test_network('pxeboot',
constants.NETWORK_TYPE_PXEBOOT, constants.NETWORK_TYPE_PXEBOOT,
self.pxeboot_subnet) self.pxeboot_subnets,
link_addresses=True)
self._create_test_network('management', self._create_test_network('management',
constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_MGMT,
self.mgmt_subnet) self.mgmt_subnets,
link_addresses=True)
self._create_test_network('oam', self._create_test_network('oam',
constants.NETWORK_TYPE_OAM, constants.NETWORK_TYPE_OAM,
self.oam_subnet) self.oam_subnets,
link_addresses=True)
self._create_test_network('cluster-host', self._create_test_network('cluster-host',
constants.NETWORK_TYPE_CLUSTER_HOST, constants.NETWORK_TYPE_CLUSTER_HOST,
self.cluster_host_subnet) self.cluster_host_subnets,
link_addresses=True)
self._create_test_network('cluster-pod', self._create_test_network('cluster-pod',
constants.NETWORK_TYPE_CLUSTER_POD, constants.NETWORK_TYPE_CLUSTER_POD,
self.cluster_pod_subnet) self.cluster_pod_subnets)
self._create_test_network('cluster-service', self._create_test_network('cluster-service',
constants.NETWORK_TYPE_CLUSTER_SERVICE, constants.NETWORK_TYPE_CLUSTER_SERVICE,
self.cluster_service_subnet) self.cluster_service_subnets)
self._create_test_network('storage', self._create_test_network('storage',
constants.NETWORK_TYPE_STORAGE, constants.NETWORK_TYPE_STORAGE,
self.storage_subnet) self.storage_subnets,
link_addresses=True)
self._create_test_network('admin', self._create_test_network('admin',
constants.NETWORK_TYPE_ADMIN, constants.NETWORK_TYPE_ADMIN,
self.admin_subnet) self.admin_subnets,
link_addresses=True)
self._create_test_network('system-controller', self._create_test_network('system-controller',
constants.NETWORK_TYPE_SYSTEM_CONTROLLER, constants.NETWORK_TYPE_SYSTEM_CONTROLLER,
self.system_controller_subnet) self.system_controller_subnets)
self._create_test_network('system-controller-oam', self._create_test_network('system-controller-oam',
constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM, constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM,
self.system_controller_oam_subnet) self.system_controller_oam_subnets)
def _create_test_datanetworks(self): def _create_test_datanetworks(self):
@ -319,17 +453,26 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self._create_test_datanetwork('data1', self._create_test_datanetwork('data1',
constants.DATANETWORK_TYPE_VLAN) constants.DATANETWORK_TYPE_VLAN)
def _create_test_addresses(self, hostnames, subnet, network_type, def _add_address_to_index(self, address):
self.addresses_by_id[address.id] = address
def _create_test_address(self, **kwargs):
address = dbutils.create_test_address(**kwargs)
self._add_address_to_index(address)
return address
def _create_test_addresses(self, hostnames, subnets, network_type,
start=1, stop=None): start=1, stop=None):
ips = itertools.islice(subnet, start, stop)
addresses = [] addresses = []
for name in hostnames: for subnet in subnets:
address = dbutils.create_test_address( ips = itertools.islice(subnet, start, stop)
name=utils.format_address_name(name, network_type), for name in hostnames:
family=subnet.version, address = self._create_test_address(
prefix=subnet.prefixlen, name=utils.format_address_name(name, network_type),
address=str(next(ips))) family=subnet.version,
addresses.append(address) prefix=subnet.prefixlen,
address=str(next(ips)))
addresses.append(address)
return addresses return addresses
def _create_test_static_ips(self): def _create_test_static_ips(self):
@ -341,36 +484,35 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
] ]
self._create_test_addresses( self._create_test_addresses(
hostnames, self.pxeboot_subnet, hostnames, self.pxeboot_subnets,
constants.NETWORK_TYPE_PXEBOOT) constants.NETWORK_TYPE_PXEBOOT)
self.mgmt_addresses = self._create_test_addresses( self.mgmt_addresses = self._create_test_addresses(
hostnames, hostnames, self.mgmt_subnets,
self.mgmt_subnet,
constants.NETWORK_TYPE_MGMT) constants.NETWORK_TYPE_MGMT)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.oam_subnet, hostnames, self.oam_subnets,
constants.NETWORK_TYPE_OAM) constants.NETWORK_TYPE_OAM)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.cluster_host_subnet, hostnames, self.cluster_host_subnets,
constants.NETWORK_TYPE_CLUSTER_HOST) constants.NETWORK_TYPE_CLUSTER_HOST)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.storage_subnet, hostnames, self.storage_subnets,
constants.NETWORK_TYPE_STORAGE) constants.NETWORK_TYPE_STORAGE)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.admin_subnet, hostnames, self.admin_subnets,
constants.NETWORK_TYPE_ADMIN) constants.NETWORK_TYPE_ADMIN)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.system_controller_subnet, hostnames, self.system_controller_subnets,
constants.NETWORK_TYPE_SYSTEM_CONTROLLER) constants.NETWORK_TYPE_SYSTEM_CONTROLLER)
self._create_test_addresses( self._create_test_addresses(
hostnames, self.system_controller_oam_subnet, hostnames, self.system_controller_oam_subnets,
constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM) constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM)
def _create_test_oam(self): def _create_test_oam(self):
@ -386,9 +528,24 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
] ]
self._create_test_addresses( self._create_test_addresses(
hostnames, self.multicast_subnet, hostnames, self.multicast_subnets,
constants.NETWORK_TYPE_MULTICAST) constants.NETWORK_TYPE_MULTICAST)
def _get_all_networks(self):
return self.networks_by_id.values()
def _find_network_by_type(self, networktype):
return self.networks_by_type.get(networktype, None)
def _find_network_by_id(self, network_id):
return self.networks_by_id.get(network_id, None)
def _find_network_address_pools(self, network_id):
return self.address_pools_by_network_id.get(network_id, [])
def _find_address_by_id(self, address_id):
return self.addresses_by_id.get(address_id, None)
@six.add_metaclass(abc.ABCMeta) @six.add_metaclass(abc.ABCMeta)
class BaseHostTestCase(BaseSystemTestCase): class BaseHostTestCase(BaseSystemTestCase):
@ -484,10 +641,10 @@ class BaseHostTestCase(BaseSystemTestCase):
def _create_test_host_addresses(self, hostname): def _create_test_host_addresses(self, hostname):
self._create_test_addresses( self._create_test_addresses(
[hostname], self.mgmt_subnet, [hostname], self.mgmt_subnets,
constants.NETWORK_TYPE_MGMT, start=10) constants.NETWORK_TYPE_MGMT, start=10)
self._create_test_addresses( self._create_test_addresses(
[hostname], self.cluster_host_subnet, [hostname], self.cluster_host_subnets,
constants.NETWORK_TYPE_CLUSTER_HOST, start=10) constants.NETWORK_TYPE_CLUSTER_HOST, start=10)
def _create_test_host_platform_interface(self, host): def _create_test_host_platform_interface(self, host):
@ -721,7 +878,8 @@ class OpenstackTestCase(AppTestCase):
self._create_test_host_platform_interface(self.host2) self._create_test_host_platform_interface(self.host2)
self._create_test_host_data_interface(self.host2) self._create_test_host_data_interface(self.host2)
self.fake_hieradata = "" self.fake_hieradata = ""
with open(os.path.join(os.getcwd(), "sysinv", "tests", "puppet", "fake_hieradata.yaml")) as fake_data: with open(os.path.join(os.getcwd(), "sysinv", "tests",
"puppet", "fake_hieradata.yaml")) as fake_data:
self.fake_hieradata = fake_data.read() self.fake_hieradata = fake_data.read()

View File

@ -62,13 +62,14 @@ class DbNetworkTestCaseIPv4(base.BaseHostTestCase):
def test_network_addrpool_db(self): def test_network_addrpool_db(self):
to_add = [ to_add = [
(constants.NETWORK_TYPE_MGMT, ('management', 'management-ipv6')), (constants.NETWORK_TYPE_MGMT, ('management-ipv4', 'management-ipv6')),
(constants.NETWORK_TYPE_OAM, ('oam', 'oam-ipv6')), (constants.NETWORK_TYPE_OAM, ('oam-ipv4', 'oam-ipv6')),
(constants.NETWORK_TYPE_ADMIN, ('admin', 'admin-ipv6')), (constants.NETWORK_TYPE_ADMIN, ('admin-ipv4', 'admin-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_HOST, ('cluster-host', 'cluster-host-ipv6')), (constants.NETWORK_TYPE_CLUSTER_HOST, ('cluster-host-ipv4', 'cluster-host-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_POD, ('cluster-pod', 'cluster-pod-ipv6')), (constants.NETWORK_TYPE_CLUSTER_POD, ('cluster-pod-ipv4', 'cluster-pod-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_SERVICE, ('cluster-service', 'cluster-service-ipv6')), (constants.NETWORK_TYPE_CLUSTER_SERVICE, ('cluster-service-ipv4',
(constants.NETWORK_TYPE_STORAGE, ('storage', 'storage-ipv6')) 'cluster-service-ipv6')),
(constants.NETWORK_TYPE_STORAGE, ('storage-ipv4', 'storage-ipv6'))
] ]
# test network_addrpool_create() # test network_addrpool_create()
@ -101,16 +102,16 @@ class DbNetworkTestCaseIPv4(base.BaseHostTestCase):
net_pools = self.dbapi.network_addrpool_get_by_network_id(net.id) net_pools = self.dbapi.network_addrpool_get_by_network_id(net.id)
self.assertEqual(len(net_pools), 2) self.assertEqual(len(net_pools), 2)
self.assertEqual(net_pools[0].network_type, constants.NETWORK_TYPE_MGMT) self.assertEqual(net_pools[0].network_type, constants.NETWORK_TYPE_MGMT)
self.assertEqual(net_pools[0].address_pool_name, "management") self.assertEqual(net_pools[0].address_pool_name, "management-ipv4")
self.assertEqual(net_pools[1].network_type, constants.NETWORK_TYPE_MGMT) self.assertEqual(net_pools[1].network_type, constants.NETWORK_TYPE_MGMT)
self.assertEqual(net_pools[1].address_pool_name, "management-ipv6") self.assertEqual(net_pools[1].address_pool_name, "management-ipv6")
# test network_addrpool_get_by_pool_id() # test network_addrpool_get_by_pool_id()
pool4 = self.dbapi.address_pool_query({'name': 'management'}) pool4 = self.dbapi.address_pool_query({'name': 'management-ipv4'})
net_pools = self.dbapi.network_addrpool_get_by_pool_id(pool4.id) net_pools = self.dbapi.network_addrpool_get_by_pool_id(pool4.id)
self.assertEqual(len(net_pools), 1) self.assertEqual(len(net_pools), 1)
self.assertEqual(net_pools[0].address_pool_id, pool4.id) self.assertEqual(net_pools[0].address_pool_id, pool4.id)
self.assertEqual(net_pools[0].address_pool_name, 'management') self.assertEqual(net_pools[0].address_pool_name, 'management-ipv4')
# test network_addrpool_query() # test network_addrpool_query()
net_pool_q = self.dbapi.network_addrpool_query({'address_pool_id': pool4.id, net_pool_q = self.dbapi.network_addrpool_query({'address_pool_id': pool4.id,
@ -152,7 +153,7 @@ class DbNetworkTestCaseIPv4(base.BaseHostTestCase):
'controller-mgmt', constants.IPV6_FAMILY) 'controller-mgmt', constants.IPV6_FAMILY)
self._create_test_addresses(hostnames=[constants.CONTROLLER_HOSTNAME], self._create_test_addresses(hostnames=[constants.CONTROLLER_HOSTNAME],
subnet=netaddr.IPNetwork('fd01::/64'), subnets=[netaddr.IPNetwork('fd01::/64')],
network_type=constants.NETWORK_TYPE_MGMT) network_type=constants.NETWORK_TYPE_MGMT)
addr = self.dbapi.address_get_by_name_and_family('controller-mgmt', addr = self.dbapi.address_get_by_name_and_family('controller-mgmt',

View File

@ -730,31 +730,39 @@ def create_test_address_pool(**kw):
controller1_address = address_pool.pop('controller1_address', None) controller1_address = address_pool.pop('controller1_address', None)
gateway_address = address_pool.pop('gateway_address', None) gateway_address = address_pool.pop('gateway_address', None)
addresses = []
if floating_address: if floating_address:
try: try:
fl_addr = dbapi.address_get_by_address(floating_address) fl_addr = dbapi.address_get_by_address(floating_address)
addresses.append(fl_addr)
address_pool['floating_address_id'] = fl_addr.id address_pool['floating_address_id'] = fl_addr.id
except Exception: except Exception:
pass pass
if controller0_address: if controller0_address:
try: try:
c0_addr = dbapi.address_get_by_address(controller0_address) c0_addr = dbapi.address_get_by_address(controller0_address)
addresses.append(c0_addr)
address_pool['controller0_address_id'] = c0_addr.id address_pool['controller0_address_id'] = c0_addr.id
except Exception: except Exception:
pass pass
if controller1_address: if controller1_address:
try: try:
c1_addr = dbapi.address_get_by_address(controller1_address) c1_addr = dbapi.address_get_by_address(controller1_address)
addresses.append(c1_addr)
address_pool['controller1_address_id'] = c1_addr.id address_pool['controller1_address_id'] = c1_addr.id
except Exception: except Exception:
pass pass
if gateway_address: if gateway_address:
try: try:
c1_addr = dbapi.address_get_by_address(gateway_address) gw_addr = dbapi.address_get_by_address(gateway_address)
address_pool['gateway_address_id'] = c1_addr.id addresses.append(gw_addr)
address_pool['gateway_address_id'] = gw_addr.id
except Exception: except Exception:
pass pass
return dbapi.address_pool_create(address_pool) db_address_pool = dbapi.address_pool_create(address_pool)
for address in addresses:
dbapi.address_update(address.uuid, {'address_pool_id': db_address_pool.id})
return db_address_pool
def get_test_address(**kw): def get_test_address(**kw):
@ -1363,6 +1371,18 @@ def create_test_interface(**kw):
forihostid = kw.get('forihostid') forihostid = kw.get('forihostid')
interface_obj = dbapi.iinterface_create(forihostid, interface) interface_obj = dbapi.iinterface_create(forihostid, interface)
ipv4_mode = interface.get('ipv4_mode', None)
if ipv4_mode:
dbapi.address_mode_update(interface_obj.id,
{'family': constants.IPV4_FAMILY, 'mode': ipv4_mode})
interface_obj.ipv4_mode = ipv4_mode
ipv6_mode = interface.get('ipv6_mode', None)
if ipv6_mode:
dbapi.address_mode_update(interface_obj.id,
{'family': constants.IPV6_FAMILY, 'mode': ipv6_mode})
interface_obj.ipv6_mode = ipv6_mode
# assign the network to the interface # assign the network to the interface
for network in networks_list: for network in networks_list:
if not network: if not network:

File diff suppressed because it is too large Load Diff

View File

@ -49,11 +49,6 @@ class NetworkingTestCaseMixin(base.PuppetTestCaseMixin):
class_name = self.__class__.__name__ class_name = self.__class__.__name__
return os.path.join(hiera_directory, class_name) + ".yaml" return os.path.join(hiera_directory, class_name) + ".yaml"
def _find_network_by_type(self, networktype):
for network in self.networks:
if network['type'] == networktype:
return network
def _get_network_ids_by_type(self, networktype): def _get_network_ids_by_type(self, networktype):
if isinstance(networktype, list): if isinstance(networktype, list):
networktypelist = networktype networktypelist = networktype
@ -259,11 +254,11 @@ class NetworkingTestTestCaseControllerDualStackIPv4Primary(NetworkingTestCaseMix
subnet=cfgdata[1][0]) subnet=cfgdata[1][0])
network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=pool.id, network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=pool.id,
network_id=net.id) network_id=net.id)
self._create_test_addresses(hostnames=hosts, subnet=cfgdata[1][0], self._create_test_addresses(hostnames=hosts, subnets=[cfgdata[1][0]],
network_type=cfgdata[0], start=2) network_type=cfgdata[0], start=2)
if cfgdata[0] in [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM]: if cfgdata[0] in [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM]:
self._create_test_addresses(hostnames=[constants.CONTROLLER_GATEWAY], self._create_test_addresses(hostnames=[constants.CONTROLLER_GATEWAY],
subnet=cfgdata[1][0], subnets=[cfgdata[1][0]],
network_type=cfgdata[0], start=1, stop=2) network_type=cfgdata[0], start=1, stop=2)
self.network_addrpools.append(network_addrpool) self.network_addrpools.append(network_addrpool)
@ -398,11 +393,11 @@ class NetworkingTestTestCaseControllerDualStackIPv6Primary(NetworkingTestCaseMix
subnet=cfgdata[1][0]) subnet=cfgdata[1][0])
network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=pool.id, network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=pool.id,
network_id=net.id) network_id=net.id)
self._create_test_addresses(hostnames=hosts, subnet=cfgdata[1][0], self._create_test_addresses(hostnames=hosts, subnets=[cfgdata[1][0]],
network_type=cfgdata[0], start=2) network_type=cfgdata[0], start=2)
if cfgdata[0] in [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM]: if cfgdata[0] in [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM]:
self._create_test_addresses(hostnames=[constants.CONTROLLER_GATEWAY], self._create_test_addresses(hostnames=[constants.CONTROLLER_GATEWAY],
subnet=cfgdata[1][0], subnets=[cfgdata[1][0]],
network_type=cfgdata[0], start=1, stop=2) network_type=cfgdata[0], start=1, stop=2)
self.network_addrpools.append(network_addrpool) self.network_addrpools.append(network_addrpool)

View File

@ -61,11 +61,6 @@ class PlatformFirewallTestCaseMixin(base.PuppetTestCaseMixin):
def _setup_configuration(self): def _setup_configuration(self):
pass pass
def _find_network_by_type(self, networktype):
for network in self.networks:
if network['type'] == networktype:
return network
def _get_network_ids_by_type(self, networktype): def _get_network_ids_by_type(self, networktype):
if isinstance(networktype, list): if isinstance(networktype, list):
networktypelist = networktype networktypelist = networktype

View File

@ -102,6 +102,7 @@ commands =
scripts/query_pci_id scripts/query_pci_id
[testenv:py39] [testenv:py39]
passenv = TOX_DEBUG_LEVEL
commands = commands =
stestr run {posargs} stestr run {posargs}
stestr slowest stestr slowest