Update network interface puppet resource gen to support dual-stack

This change updates the puppet resource generation logic for network
interfaces to suport dual-stack.

Change summary
==============

- Aliases / labels
    Previously, each alias was associated to a specific network. Now,
    since more than one address can be associated to the same network,
    the aliases are also associated to addresses. The label name is
    now :<network_id>-<address_id>. The network_id is 0 if there's no
    network associated with the alias, that's the case for the base
    interface config or for the cases where the address is not
    associated to a network. The address_id is 0 if there's no address
    associated with the alias, which is the case for the base config
    and for when there's no static address associated to the network,
    i.e. the method is DHCP.

- Static addresses
    Previously, interfaces with more than one static addresses not
    associated with pools would be assigned just the first one. Now,
    an alias config is generated for each address.

- CentOS compatibility
    All the code related to CentOS was removed.

- Duplex-direct mode
    Duplex-direct systems must have DAD disabled for management and
    cluster-host interfaces. The disable DAD command is now generated
    only in the base interface config for all types of interfaces.

- Address pool names
    The change assumes a new standard for address pool names, they will
    be formed by the old names with the suffixes '-ipv4' or '-ipv6'.
    For example: management-ipv4, management-ipv6. Since other systems
    that rely on the previous standard are not yet upgraded to
    dual-stack, the constant DUAL_STACK_COMPATIBILITY_MODE was
    introduced to control resource generation and validation logic in a
    way that assures compatibility. The constant and the conditionals
    will be removed once the other modules are updated. The
    conditionals were implemented more as a way to highlight which
    parts of the code are affected and make the changes easier in the
    future.

- Tests / DB Base
    The base class for tests was updated to generate more consistent
    database states. Mixins for dual-stack cases were also created.

- Tests / Interface
    Most of the test functions in the class InterfaceTestCase caused
    unnecessary updates to the database and the context. The class
    was splitted in two, the first one containing the tests that only
    need the basic database setup (controller, one interface
    associated with the mgmt network), and the other one for the tests
    that need different setups.
    A new fixture was created to test multiple system configs (IPv4,
    IPv6, dual-stack), which inspects in detail the generated
    hieradata. The tests associated with the InterfaceHostV6TestCase
    were moved to the new fixture, and new ones were introduced.

Test plan
=========

Online setup tests
------------------

System: STANDARD (2 Controllers, 2 Storages, 1 Worker)

Stack setups:
  - Single stack IPv4
  - Single stack IPv6
  - Dual stack, primary IPv4
  - Dual stack, primary IPv6

[PASS] TC1 - Online setup, regular ethernet
    mgmt0 (Ethernet) -> PXEBOOT, MGMT, CLUSTER_HOST

[PASS] TC2 - Online setup, VLAN over ethernet
    pxe0 (Ethernet) -> PXEBOOT
    mgmt0 (VLAN over pxe0) -> MGMT, CLUSTER_HOST

[PASS] TC3 - Online setup, bondig
    mgmt0 (Bond) -> PXEBOOT, MGMT, CLUSTER_HOST

[PASS] TC4 - Online setup, VLAN over bonding
    pxe0 (Bond) -> PXEBOOT
    mgmt0 (VLAN over pxe0) -> MGMT, CLUSTER_HOST

Installation tests
------------------

Systems:
  - AIO-SX
  - AIO-DX
  - Standard (2 Controllers, 2 Storages, 1 Worker)

[PASS] TC5 - Regular installation on VirtualBox, IPv4

[PASS] TC6 - Regular installation on VirtualBox, IPv6

Data interface tests
--------------------

System: AIO-DX

Setup:
    data0 -> Ethernet, ipv4_mode=static, ipv6_mode=static
    data1 -> VLAN on top of data0, ipv4_mode=static, ipv6_mode=static

For both interfaces, the following was performed:

[PASS] TC7 - Add static IPv4 address
[PASS] TC8 - Add static IPv6 address
[PASS] TC9 - Add IPv4 route
[PASS] TC10 - Add IPv6 route
[PASS] TC11 - Remove IPv4 route
[PASS] TC12 - Remove IPv6 route
[PASS] TC13 - Remove static IPv4 address
[PASS] TC14 - Remove static IPv6 address

Story: 2011027
Task: 49815
Change-Id: Ib9603cbd444b21aefbcd417780a12c079f3d0b0f
Signed-off-by: Lucas Ratusznei Fonseca <lucas.ratuszneifonseca@windriver.com>
This commit is contained in:
Lucas Ratusznei Fonseca 2024-03-25 13:53:16 -03:00
parent e4b32b7e16
commit ff3a5d2341
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

@ -2502,3 +2502,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):

View File

@ -6,7 +6,6 @@
import collections import collections
import copy import copy
import os
import re import re
import six import six
@ -129,6 +128,10 @@ class InterfacePuppet(base.BasePuppet):
def _create_interface_context(self, host): def _create_interface_context(self, host):
host_interfaces = self.dbapi.iinterface_get_by_ihost(host.uuid) host_interfaces = self.dbapi.iinterface_get_by_ihost(host.uuid)
networks = self._get_network_type_index()
address_pools = self._get_address_pool_index()
network_address_pools = self._get_network_addresspool_index()
addresses = self._get_address_interface_name_index(host)
context = { context = {
'hostname': host.hostname, 'hostname': host.hostname,
'personality': host.personality, 'personality': host.personality,
@ -137,14 +140,17 @@ class InterfacePuppet(base.BasePuppet):
'system_mode': self._get_system().system_mode, 'system_mode': self._get_system().system_mode,
'ports': self._get_port_interface_id_index(host), 'ports': self._get_port_interface_id_index(host),
'interfaces': self._get_interface_name_index(host_interfaces), 'interfaces': self._get_interface_name_index(host_interfaces),
'interface_networks': self._get_interface_network_index(
host_interfaces, addresses, networks, address_pools, network_address_pools),
'interfaces_datanets': self._get_interface_name_datanets( 'interfaces_datanets': self._get_interface_name_datanets(
host.hostname, host_interfaces), host.hostname, host_interfaces),
'devices': self._get_port_pciaddr_index(host), 'devices': self._get_port_pciaddr_index(host),
'addresses': self._get_address_interface_name_index(host), 'addresses': addresses,
'routes': self._get_routes_interface_name_index(host), 'routes': self._get_routes_interface_name_index(host),
'networks': self._get_network_type_index(), 'networks': networks,
'gateways': self._get_gateway_index(), 'address_pools': address_pools,
'floatingips': self._get_floating_ip_index(), 'floatingips': self._get_floating_ip_index(networks, address_pools,
network_address_pools),
'datanets': self._get_datanetworks(host), 'datanets': self._get_datanetworks(host),
'vswitchtype': self._vswitch_type(), 'vswitchtype': self._vswitch_type(),
} }
@ -196,6 +202,61 @@ class InterfacePuppet(base.BasePuppet):
""" """
return interface._get_address_interface_name_index(self.dbapi, host) return interface._get_address_interface_name_index(self.dbapi, host)
def _get_interface_network_index(self, host_interfaces, address_index, network_type_index,
addrpool_index, network_addrpool_index):
"""
Builds a dictionary that associates interfaces with networks and addresses.
Format:
{
<interface_name>: {
<network_id or None>: {
'network': <network_object or None>,
'addresses': [ <address 1>, <address 2>, ... ]
}
}
}
"""
network_id_index = {}
for network in network_type_index.values():
network_id_index[network.id] = network
interface_index = {}
for iface in host_interfaces:
interface_dict = {None: {'network': None, 'addresses': []}}
for networktype in iface.networktypelist:
network = network_type_index[networktype]
interface_dict[network.id] = {'network': network, 'addresses': []}
interface_index[iface.ifname] = interface_dict
for address_list in address_index.values():
for address in address_list:
addrpool = addrpool_index.get(address.pool_uuid, None)
network_addrpool = network_addrpool_index.get(address.pool_uuid, None)
network = None
if addrpool and network_addrpool:
network = network_id_index[network_addrpool.network_id]
network_id = network.id if network else None
interface_entry = interface_index.get(address.ifname, None)
if not interface_entry:
continue
network_entry = interface_entry.get(network_id, None)
if not network_entry:
network_entry = {
'network': network,
'addresses': []
}
interface_entry[network_id] = network_entry
network_entry['addresses'].append(address)
return interface_index
def _get_routes_interface_name_index(self, host): def _get_routes_interface_name_index(self, host):
""" """
Builds a dictionary of route lists indexed by interface name. Builds a dictionary of route lists indexed by interface name.
@ -216,118 +277,55 @@ class InterfacePuppet(base.BasePuppet):
networks[network['type']] = network networks[network['type']] = network
return networks return networks
def _get_gateway_index(self): def _get_address_pool_index(self):
""" addrpool_index = {}
Builds a dictionary of gateway IP addresses indexed by network type. addrpools = self.dbapi.address_pools_get_all()
""" for addrpool in addrpools:
gateways = {} addrpool_index[addrpool.uuid] = addrpool
try: return addrpool_index
mgmt_address = self._get_address_by_name(
constants.CONTROLLER_GATEWAY, constants.NETWORK_TYPE_MGMT)
gateways.update({
constants.NETWORK_TYPE_MGMT: mgmt_address.address})
except exception.AddressNotFoundByName:
pass
try: def _get_network_addresspool_index(self):
oam_address = self._get_address_by_name( network_addrpool_index = {}
constants.CONTROLLER_GATEWAY, constants.NETWORK_TYPE_OAM) network_addrpools = self.dbapi.network_addrpool_get_all()
gateways.update({ for network_addrpool in network_addrpools:
constants.NETWORK_TYPE_OAM: oam_address.address}) network_addrpool_index[network_addrpool.address_pool_uuid] = network_addrpool
except exception.AddressNotFoundByName: return network_addrpool_index
pass
return gateways def _get_floating_ip_index(self, networks, address_pools, network_address_pools):
def _get_floating_ip_index(self):
""" """
Builds a dictionary of floating ip addresses indexed by network type. Builds a dictionary of floating ip addresses indexed by network type.
""" """
mgmt_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_MGMT)
mgmt_floating_ip = (str(mgmt_address.address) + '/' + networktypes = [
str(mgmt_address.prefix)) constants.NETWORK_TYPE_MGMT,
constants.NETWORK_TYPE_PXEBOOT,
floating_ips = { constants.NETWORK_TYPE_CLUSTER_HOST,
constants.NETWORK_TYPE_MGMT: mgmt_floating_ip constants.NETWORK_TYPE_IRONIC,
} constants.NETWORK_TYPE_STORAGE,
constants.NETWORK_TYPE_ADMIN
try: ]
pxeboot_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_PXEBOOT)
pxeboot_floating_ip = (str(pxeboot_address.address) + '/' +
str(pxeboot_address.prefix))
floating_ips.update({
constants.NETWORK_TYPE_PXEBOOT: pxeboot_floating_ip,
})
except exception.AddressNotFoundByName:
pass
system = self._get_system() system = self._get_system()
if system.system_mode != constants.SYSTEM_MODE_SIMPLEX: if system.system_mode != constants.SYSTEM_MODE_SIMPLEX:
oam_address = self._get_address_by_name( networktypes.append(constants.NETWORK_TYPE_OAM)
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_OAM)
oam_floating_ip = (str(oam_address.address) + '/' + network_index = {}
str(oam_address.prefix)) for network in networks.values():
if network.type in networktypes:
floating_ips.update({ network_index[network.id] = network
constants.NETWORK_TYPE_OAM: oam_floating_ip
})
floating_ips = collections.defaultdict(list)
for network_address_pool in network_address_pools.values():
network = network_index.get(network_address_pool.network_id, None)
if not network:
continue
address_pool = address_pools[network_address_pool.address_pool_uuid]
if not address_pool.floating_address_id:
continue
try: try:
cluster_address = self._get_address_by_name( address = self.dbapi.address_get_by_id(address_pool.floating_address_id)
constants.CONTROLLER_HOSTNAME, floating_ips[network.type].append(address)
constants.NETWORK_TYPE_CLUSTER_HOST) except exception.AddressNotFoundById:
if cluster_address:
cluster_floating_ip = (str(cluster_address.address) + '/' +
str(cluster_address.prefix))
floating_ips.update({
constants.NETWORK_TYPE_CLUSTER_HOST: cluster_floating_ip
})
except exception.AddressNotFoundByName:
pass
try:
ironic_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_IRONIC)
ironic_floating_ip = (str(ironic_address.address) + '/' +
str(ironic_address.prefix))
floating_ips.update({
constants.NETWORK_TYPE_IRONIC: ironic_floating_ip,
})
except exception.AddressNotFoundByName:
pass
try:
storage_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_STORAGE)
storage_floating_ip = (str(storage_address.address) + '/' +
str(storage_address.prefix))
floating_ips.update({
constants.NETWORK_TYPE_STORAGE: storage_floating_ip,
})
except exception.AddressNotFoundByName:
pass
try:
admin_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_ADMIN)
admin_floating_ip = (str(admin_address.address) + '/' +
str(admin_address.prefix))
floating_ips.update({
constants.NETWORK_TYPE_ADMIN: admin_floating_ip,
})
except exception.AddressNotFoundByName:
pass pass
return floating_ips return floating_ips
@ -666,82 +664,46 @@ def _set_address_netmask(address):
return address return address
def get_interface_primary_address(context, iface, network_id=None): def get_gateway_address(context, network, address):
""" """
Determine the primary IP address on an interface (if any). If multiple Gets the corresponding gateway for the provided address
addresses exist then the first address is returned.
""" """
addresses = context['addresses'].get(iface['ifname'], [])
if len(addresses) > 0 and network_id is None:
return _set_address_netmask(addresses[0])
elif network_id:
for address in addresses:
net = find_network_by_pool_uuid(context,
address.pool_uuid)
if net and network_id == net.id:
return _set_address_netmask(address)
addrpool = context['address_pools'].get(address.pool_uuid, None)
def get_interface_address_family(context, iface, network_id=None): if not addrpool:
"""
Determine the IP family/version of the interface primary address. If there
is no address then the IPv4 family identifier is returned so that an
appropriate default is always present in interface configurations.
"""
address = get_interface_primary_address(context, iface, network_id)
if not address:
return 'inet' # default to ipv4
elif IPAddress(address['address']).version == 4:
return 'inet'
elif IPAddress(address['address']).version == 6:
return 'inet6'
def get_interface_gateway_address(context, networktype):
"""
Determine if the interface has a default gateway.
"""
if (networktype == constants.NETWORK_TYPE_MGMT and
context['personality'] in [constants.WORKER, constants.STORAGE]):
address = context['floatingips'].get(networktype, None)
if address is None:
return None return None
return address.split('/')[0]
return context['gateways'].get(networktype, None) if (network and network.type == constants.NETWORK_TYPE_MGMT and
context['personality'] in [constants.WORKER, constants.STORAGE]):
gateway_address = addrpool.floating_address
else:
gateway_address = addrpool.gateway_address
return gateway_address
def get_interface_address_method(context, iface, network_id=None): def get_interface_address_method(context, iface, network=None, address=None):
""" networktype = network.type if network else None
Determine what type of interface to configure for each network type.
"""
networktype = find_networktype_by_network_id(context, network_id)
has_static_addr = False has_static_addr = False
if (iface.ipv4_mode == constants.IPV4_STATIC or iface.ipv6_mode == constants.IPV6_STATIC): if address:
if address.family == constants.IPV4_FAMILY and iface.ipv4_mode == constants.IPV4_STATIC:
has_static_addr = True
elif address.family == constants.IPV6_FAMILY and iface.ipv6_mode == constants.IPV6_STATIC:
has_static_addr = True has_static_addr = True
if iface.ifclass == constants.INTERFACE_CLASS_DATA: if iface.ifclass == constants.INTERFACE_CLASS_DATA:
if is_syscfg_network():
if is_vswitch_type_unaccelerated(context):
return STATIC_METHOD
else:
if has_static_addr: if has_static_addr:
return STATIC_METHOD return STATIC_METHOD
# All data interfaces configured in the kernel because they are not # All data interfaces configured in the kernel because they are not
# natively supported in vswitch or need to be shared with the kernel # natively supported in vswitch or need to be shared with the kernel
# because of a platform VLAN should be left as manual config # because of a platform VLAN should be left as manual config
return MANUAL_METHOD return MANUAL_METHOD
elif (iface.ifclass == constants.INTERFACE_CLASS_PLATFORM and elif (iface.ifclass == constants.INTERFACE_CLASS_PLATFORM and networktype is None):
networktype is None and has_static_addr): if has_static_addr:
# On Debian, interfaces of networktype:None with alias should be
# manual method (i.e: lo) and alias will be Static method (i.e: lo:1)
if not is_syscfg_network() and len(iface.networktypelist) > 1:
return MANUAL_METHOD
# Allow platform-class interface with ipv4 mode set to static to
# have static ip address
return STATIC_METHOD return STATIC_METHOD
return MANUAL_METHOD
elif not iface.ifclass or iface.ifclass == constants.INTERFACE_CLASS_NONE \ elif not iface.ifclass or iface.ifclass == constants.INTERFACE_CLASS_NONE \
or not networktype: or not networktype:
# Interfaces that are configured purely as a dependency from other # Interfaces that are configured purely as a dependency from other
@ -871,42 +833,21 @@ def get_basic_network_config(ifname, ensure='present',
'onboot': onboot, 'onboot': onboot,
'options': {}} 'options': {}}
if mtu: if mtu:
if is_syscfg_network():
config['mtu'] = str(mtu)
else:
config['options']['mtu'] = str(mtu) config['options']['mtu'] = str(mtu)
return config return config
def get_bridge_network_config(context, iface): def is_disable_dad_required(iface, network=None):
""" """
Builds a network config dictionary for bridge interface resource. Disable DAD command is included in the base interface config, only for interfaces associated
with management and cluster-host networks.
""" """
os_ifname = get_interface_os_ifname(context, iface)
os_ifname = 'br-' + os_ifname
method = get_interface_address_method(context, iface)
family = get_interface_address_family(context, iface)
config = get_basic_network_config(
os_ifname, method=method, family=family)
config['options']['TYPE'] = 'Bridge'
return config
if network:
def is_disable_dad_required(context, iface, config, network_id=None): return False
""" networks = [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_CLUSTER_HOST]
Determine whether DAD is required to be disabled. for networktype in iface.networktypelist:
If mgmt and cluster-host are separate vlans, the vlan has DAD disabled. if networktype in networks:
If the vlans are shared between networks, the DAD is disabled
on the parent vlan interface, not the alias interfaces.
If mgmt and cluster-host are not vlan, the interfaces have DAD disabled.
"""
networktype = find_networktype_by_network_id(context, network_id)
if len(iface.networktypelist) > 1:
if (iface['iftype'] == constants.INTERFACE_TYPE_VLAN and
network_id is None):
return True
elif (networktype and networktype in [constants.NETWORK_TYPE_MGMT,
constants.NETWORK_TYPE_CLUSTER_HOST]):
return True return True
return False return False
@ -922,21 +863,18 @@ def get_interface_sysctl_ifname(context, iface):
return os_ifname return os_ifname
def get_duplex_direct_network_config(context, iface, config, network_id): def get_duplex_direct_network_config(context, iface, config, network):
""" """
Disable dad on the specified interface for duplex-direct config Disable dad on the specified interface for duplex-direct config
""" """
if iface['iftype'] == constants.INTERFACE_TYPE_AE: if iface['iftype'] == constants.INTERFACE_TYPE_AE:
networktype = find_networktype_by_network_id(context, network_id)
if (networktype and networktype in [constants.NETWORK_TYPE_MGMT,
constants.NETWORK_TYPE_CLUSTER_HOST]):
command = ("/sbin/modprobe bonding; " command = ("/sbin/modprobe bonding; "
"grep %s /sys/class/net/bonding_masters || " "grep %s /sys/class/net/bonding_masters || "
"echo +%s > /sys/class/net/bonding_masters" % ( "echo +%s > /sys/class/net/bonding_masters" % (
iface['ifname'], iface['ifname'])) iface['ifname'], iface['ifname']))
fill_interface_config_option_operation(config['options'], IFACE_PRE_UP_OP, command) fill_interface_config_option_operation(config['options'], IFACE_PRE_UP_OP, command)
if not is_syscfg_network() and iface['iftype'] == constants.INTERFACE_TYPE_VLAN: if iface['iftype'] == constants.INTERFACE_TYPE_VLAN:
add_vlan_interface_creation_command(context, iface, config['options']) add_vlan_interface_creation_command(context, iface, config['options'])
sysctl_ifname = get_interface_sysctl_ifname(context, iface) sysctl_ifname = get_interface_sysctl_ifname(context, iface)
@ -951,9 +889,6 @@ def get_vlan_network_config(context, iface, config):
interface. interface.
""" """
lower_os_ifname = get_lower_interface_os_ifname(context, iface) lower_os_ifname = get_lower_interface_os_ifname(context, iface)
if is_syscfg_network():
options = {'VLAN': 'yes', 'PHYSDEV': lower_os_ifname}
else:
options = {'vlan-raw-device': lower_os_ifname} options = {'vlan-raw-device': lower_os_ifname}
fill_interface_config_option_operation(options, IFACE_PRE_UP_OP, fill_interface_config_option_operation(options, IFACE_PRE_UP_OP,
'/sbin/modprobe -q 8021q') '/sbin/modprobe -q 8021q')
@ -976,28 +911,6 @@ def add_vlan_interface_creation_command(context, iface, options):
'ip link del %s' % (os_ifname)) 'ip link del %s' % (os_ifname))
def get_bond_interface_options_sysconfig(iface, primary_iface):
"""
Get the interface config attribute for bonding options
"""
ae_mode = iface['aemode']
tx_hash_policy = iface['txhashpolicy']
options = None
if ae_mode in ACTIVE_STANDBY_AE_MODES:
# Requires the active device in an active_standby LAG
# configuration to be determined based on the lowest MAC address
options = 'mode=active-backup miimon=100 primary={}'.format(primary_iface['ifname'])
if iface['primary_reselect']:
options += ' primary_reselect=%s' % iface['primary_reselect']
else:
options = 'xmit_hash_policy=%s miimon=100' % tx_hash_policy
if ae_mode in BALANCED_AE_MODES:
options = 'mode=balance-xor ' + options
elif ae_mode in LACP_AE_MODES:
options = 'mode=802.3ad lacp_rate=fast ' + options
return options
def get_bond_interface_options_ifupdown(iface, primary_iface): def get_bond_interface_options_ifupdown(iface, primary_iface):
""" """
Get the interface config attribute for bonding options Get the interface config attribute for bonding options
@ -1028,7 +941,7 @@ def get_bond_interface_options_ifupdown(iface, primary_iface):
return options return options
def get_bond_network_config(context, iface, config, network_id): def get_bond_network_config(context, iface, config):
""" """
Augments a basic config dictionary with the attributes specific to a bond Augments a basic config dictionary with the attributes specific to a bond
interface. interface.
@ -1038,12 +951,6 @@ def get_bond_network_config(context, iface, config, network_id):
bonding_options = None bonding_options = None
iface_mac = iface['imac'].rstrip() iface_mac = iface['imac'].rstrip()
if is_syscfg_network():
options['MACADDR'] = iface_mac
bonding_options = get_bond_interface_options_sysconfig(iface, primary_iface)
if bonding_options:
options['BONDING_OPTS'] = bonding_options
else:
options['hwaddress'] = iface_mac options['hwaddress'] = iface_mac
bonding_options = get_bond_interface_options_ifupdown(iface, primary_iface) bonding_options = get_bond_interface_options_ifupdown(iface, primary_iface)
if bonding_options: if bonding_options:
@ -1092,14 +999,9 @@ def get_ethernet_network_config(context, iface, config):
""" """
interface_class = iface['ifclass'] interface_class = iface['ifclass']
options = {} options = {}
# Increased to accommodate devices that require more time to
# complete link auto-negotiation
if is_syscfg_network():
options['LINKDELAY'] = '20'
if is_bridged_interface(context, iface): if is_bridged_interface(context, iface):
if is_syscfg_network(): pass
options['BRIDGE'] = get_bridge_interface_name(context, iface)
elif is_slave_interface(context, iface): elif is_slave_interface(context, iface):
if not is_data_interface(context, iface): if not is_data_interface(context, iface):
# Data interfaces that require a network configuration are not # Data interfaces that require a network configuration are not
@ -1107,11 +1009,6 @@ def get_ethernet_network_config(context, iface, config):
# rely on the Linux device driver to setup some or all functions # rely on the Linux device driver to setup some or all functions
# on the device (e.g., the Mellanox DPDK driver relies on the # on the device (e.g., the Mellanox DPDK driver relies on the
# Linux driver to set the proper MTU value). # Linux driver to set the proper MTU value).
if is_syscfg_network():
options['SLAVE'] = 'yes'
options['MASTER'] = get_master_interface(context, iface)
options['PROMISC'] = 'yes'
else:
master = get_master_interface(context, iface) master = get_master_interface(context, iface)
options['bond-master'] = master options['bond-master'] = master
osname = get_interface_os_ifname(context, iface) osname = get_interface_os_ifname(context, iface)
@ -1346,13 +1243,11 @@ def get_fpga_config(context, iface):
return config return config
def get_common_network_config(context, iface, config, network_id=None): def get_common_network_config(context, iface, config, network=None, address=None):
""" """
Augments a basic config dictionary with the attributes specific to an upper Augments a basic config dictionary with the attributes specific to an upper
layer interface (i.e., an interface that is used to terminate IP traffic). layer interface (i.e., an interface that is used to terminate IP traffic).
""" """
LOG.debug("get_common_network_config %s %s network_id=%s" %
(iface.ifname, iface.networktypelist, network_id))
os_ifname = get_interface_os_ifname(context, iface) os_ifname = get_interface_os_ifname(context, iface)
if os_ifname == config['ifname']: if os_ifname == config['ifname']:
@ -1362,55 +1257,53 @@ def get_common_network_config(context, iface, config, network_id=None):
fill_interface_config_option_operation(config['options'], IFACE_POST_UP_OP, fill_interface_config_option_operation(config['options'], IFACE_POST_UP_OP,
traffic_classifier) traffic_classifier)
method = get_interface_address_method(context, iface, network_id) method = get_interface_address_method(context, iface, network, address)
if method == STATIC_METHOD: if method == STATIC_METHOD:
address = get_interface_primary_address(context, iface, network_id)
if address: if address:
_set_address_netmask(address)
config['ipaddress'] = address['address'] config['ipaddress'] = address['address']
config['netmask'] = address['netmask'] config['netmask'] = address['netmask']
else:
LOG.info("Interface %s has no primary address" % iface['ifname'])
networktype = find_networktype_by_network_id(context, network_id) gateway = get_gateway_address(context, network, address)
gateway = get_interface_gateway_address(context, networktype)
if gateway: if gateway:
if is_syscfg_network():
config['gateway'] = gateway
else:
config['options']['gateway'] = gateway config['options']['gateway'] = gateway
return config return config
def get_final_network_config(context, iface, config, network_id=None): def get_final_network_config(context, iface, config, network=None):
""" """
Augments a basic config dictionary with the attribute that must be Augments a basic config dictionary with the attribute that must be
appended to an attribute that is already configured (e.g. pre_up) appended to an attribute that is already configured (e.g. pre_up)
""" """
# add duplex_direct specific network config # add duplex_direct specific network config
if context['system_mode'] == constants.SYSTEM_MODE_DUPLEX_DIRECT: if context['system_mode'] == constants.SYSTEM_MODE_DUPLEX_DIRECT:
if is_disable_dad_required(context, iface, config, network_id): if is_disable_dad_required(iface, network):
config = get_duplex_direct_network_config(context, iface, config, config = get_duplex_direct_network_config(context, iface, config, network)
network_id)
return config return config
def get_interface_network_config(context, iface, network_id=None): def get_interface_network_config(context, iface, network=None, address=None):
""" """
Builds a network_config resource dictionary for a given interface Builds a network_config resource dictionary for a given interface
""" """
if iface['iftype'] == constants.INTERFACE_TYPE_VF:
# Only the parent SR-IOV interface needs a network config method = get_interface_address_method(context, iface, network, address)
# if and address is present but the address mode is not static, there's
# no need to generate a labeled config for the interface
if address is not None and method == MANUAL_METHOD:
return {} return {}
# Create a basic network config resource
os_ifname = get_interface_os_ifname(context, iface) os_ifname = get_interface_os_ifname(context, iface)
method = get_interface_address_method(context, iface, network_id) family = get_address_family(address)
family = get_interface_address_family(context, iface, network_id)
# for now label all interfaces that have network_id, later we will # for now label all interfaces that have network_id, later we will
# set the definitive values # set the definitive values
if network_id: if network or address:
ifname = "%s:%d" % (os_ifname, network_id) net_num = network.id if network else 0
addr_num = address.id if address else 0
ifname = "%s:%d-%d" % (os_ifname, net_num, addr_num)
else: else:
ifname = os_ifname ifname = os_ifname
@ -1419,13 +1312,10 @@ def get_interface_network_config(context, iface, network_id=None):
ifname, method=method, family=family, mtu=mtu) ifname, method=method, family=family, mtu=mtu)
# Add options common to all top level interfaces # Add options common to all top level interfaces
config = get_common_network_config(context, iface, config, network_id) config = get_common_network_config(context, iface, config, network, address)
# ensure addresses have host scope when configured against the loopback # ensure addresses have host scope when configured against the loopback
if os_ifname == LOOPBACK_IFNAME: if os_ifname == LOOPBACK_IFNAME:
if is_syscfg_network():
options = {'SCOPE': 'scope host'}
else:
options = {'scope': 'host'} options = {'scope': 'host'}
config['options'].update(options) config['options'].update(options)
@ -1433,14 +1323,13 @@ def get_interface_network_config(context, iface, network_id=None):
if iface['iftype'] == constants.INTERFACE_TYPE_VLAN: if iface['iftype'] == constants.INTERFACE_TYPE_VLAN:
config = get_vlan_network_config(context, iface, config) config = get_vlan_network_config(context, iface, config)
elif iface['iftype'] == constants.INTERFACE_TYPE_AE: elif iface['iftype'] == constants.INTERFACE_TYPE_AE:
config = get_bond_network_config(context, iface, config, network_id) config = get_bond_network_config(context, iface, config)
else: else:
config = get_ethernet_network_config(context, iface, config) config = get_ethernet_network_config(context, iface, config)
# Add final options # Add final options
config = get_final_network_config(context, iface, config, network_id) config = get_final_network_config(context, iface, config, network)
if not is_syscfg_network():
if iface['iftype'] == constants.INTERFACE_TYPE_VLAN: if iface['iftype'] == constants.INTERFACE_TYPE_VLAN:
# When configuring a static IPv6 interface, CentOS' ifup tool uses 'ip link' # When configuring a static IPv6 interface, CentOS' ifup tool uses 'ip link'
# command to set both IPv4 and IPv6 MTU. # command to set both IPv4 and IPv6 MTU.
@ -1453,9 +1342,6 @@ def get_interface_network_config(context, iface, network_id=None):
fill_interface_config_option_operation(config['options'], IFACE_POST_UP_OP, set_mtu) fill_interface_config_option_operation(config['options'], IFACE_POST_UP_OP, set_mtu)
# disable ipv6 autoconfig # disable ipv6 autoconfig
if is_syscfg_network():
config['options'].update({'IPV6_AUTOCONF': 'no'})
else:
interface_op = IFACE_POST_UP_OP interface_op = IFACE_POST_UP_OP
if is_slave_interface(context, iface): if is_slave_interface(context, iface):
# ifupdown's ifup only runs pre-up for slave interfaces # ifupdown's ifup only runs pre-up for slave interfaces
@ -1468,14 +1354,56 @@ def get_interface_network_config(context, iface, network_id=None):
accept_redir_off = 'echo 0 > /proc/sys/net/ipv6/conf/{}/accept_redirects'.format(os_ifname) accept_redir_off = 'echo 0 > /proc/sys/net/ipv6/conf/{}/accept_redirects'.format(os_ifname)
fill_interface_config_option_operation(config['options'], interface_op, accept_redir_off) fill_interface_config_option_operation(config['options'], interface_op, accept_redir_off)
network_type = network.type if network else None
# add the description field with the database ifname and networktype if available # add the description field with the database ifname and networktype if available
if not is_syscfg_network(): config['options']['stx-description'] = f"ifname:{iface['ifname']},net:{network_type}"
networktype = find_networktype_by_network_id(context, network_id)
config['options']['stx-description'] = f"ifname:{iface['ifname']},net:{networktype}"
return config return config
def _append_interface_config(iface_configs, iface_config):
if len(iface_config) > 0:
iface_configs.append(iface_config)
def get_interface_network_configs(context, iface, network=None):
"""
Builds a list of network_config resource dictionaries for a given interface,
each corresponding to an associated address, plus the base unlabeled config
"""
if iface['iftype'] == constants.INTERFACE_TYPE_VF:
# Only the parent SR-IOV interface needs a network config
return []
iface_configs = []
network_id = network.id if network else None
network_dict = context['interface_networks'][iface.ifname][network_id]
if network:
if len(network_dict['addresses']) == 0:
iface_config = get_interface_network_config(context, iface, network)
_append_interface_config(iface_configs, iface_config)
else:
# Most basic interface config, no network no address
iface_config = get_interface_network_config(context, iface)
_append_interface_config(iface_configs, iface_config)
for address in network_dict['addresses']:
iface_config = get_interface_network_config(context, iface, network, address)
_append_interface_config(iface_configs, iface_config)
return iface_configs
def get_address_family(address):
if address and IPAddress(address['address']).version == 6:
return 'inet6'
return 'inet'
def generate_network_config(context, hiera_config, iface): def generate_network_config(context, hiera_config, iface):
""" """
Produce the puppet network config resources necessary to configure the Produce the puppet network config resources necessary to configure the
@ -1483,24 +1411,18 @@ def generate_network_config(context, hiera_config, iface):
resource, while in other cases it will emit multiple resources to create a resource, while in other cases it will emit multiple resources to create a
bridge, or to add additional route resources. bridge, or to add additional route resources.
""" """
os_ifname = get_interface_os_ifname(context, iface) os_ifname = get_interface_os_ifname(context, iface)
# Setup the default device configuration for the interface. This will be # Setup the default device configuration for the interface. This will be
# overridden if there is a specific network type configuration, otherwise # overridden if there is a specific network type configuration, otherwise
# it will act as the parent device for the aliases # it will act as the parent device for the aliases
net_config = get_interface_network_config(context, iface) networks = context['interface_networks'][iface.ifname]
if net_config: for network_dict in networks.values():
hiera_config[NETWORK_CONFIG_RESOURCE].update({ net_configs = get_interface_network_configs(context, iface, network_dict['network'])
net_config['ifname']: format_network_config(net_config) for net_config in net_configs:
}) hiera_config[NETWORK_CONFIG_RESOURCE][net_config['ifname']] = \
format_network_config(net_config)
for net_type in iface.networktypelist:
net_id = find_network_id_by_networktype(context, net_type)
net_config = get_interface_network_config(context, iface, net_id)
if net_config:
hiera_config[NETWORK_CONFIG_RESOURCE].update({
net_config['ifname']: format_network_config(net_config)
})
# Add complementary puppet resource definitions (if needed) # Add complementary puppet resource definitions (if needed)
for route in get_interface_routes(context, iface): for route in get_interface_routes(context, iface):
@ -1524,23 +1446,11 @@ def generate_network_config(context, hiera_config, iface):
}) })
def find_network_by_pool_uuid(context, pool_uuid):
for networktype, network in six.iteritems(context['networks']):
if network.pool_uuid == pool_uuid:
return network
return None
def find_network_id_by_networktype(context, networktype): def find_network_id_by_networktype(context, networktype):
for net_type, network in six.iteritems(context['networks']): network = context['networks'].get(networktype, None)
if networktype == net_type: if network:
return network.id return network.id
return None
def find_networktype_by_network_id(context, network_id):
for networktype, network in six.iteritems(context['networks']):
if network.id == network_id:
return networktype
def find_interface_by_type(context, networktype): def find_interface_by_type(context, networktype):
@ -1555,20 +1465,6 @@ def find_interface_by_type(context, networktype):
return iface return iface
def find_address_by_type(context, networktype):
"""
Lookup an address based on networktype. This is only intended for for
types that only have 1 such address per node. For example, for SDN we
only expect/support a single data IP address per node because the SDN
controller cannot support more than 1.
"""
for ifname, addresses in six.iteritems(context['addresses']):
for address in addresses:
if address['networktype'] == networktype:
return address['address'], address['prefix']
return None, None
def find_sriov_interfaces_by_driver(context, driver): def find_sriov_interfaces_by_driver(context, driver):
""" """
Lookup all interfaces based on port driver. Lookup all interfaces based on port driver.
@ -1641,8 +1537,7 @@ def process_interface_labels(config, context):
Adjust interface labeling according to ifupdown package rules and StarlingX Adjust interface labeling according to ifupdown package rules and StarlingX
requirements requirements
""" """
# This rules are a result of using Debian's ifupdown package, # This rules are a result of using Debian's ifupdown package
# StarlingX do not support dual-stack for now
# #
# Rules for label adjustment: # Rules for label adjustment:
# 1) if the interface have just one label: # 1) if the interface have just one label:
@ -1700,7 +1595,7 @@ def process_interface_labels(config, context):
networktypelist = context['interfaces'][ifname].networktypelist networktypelist = context['interfaces'][ifname].networktypelist
undeprecate = "ip -6 addr replace" + \ undeprecate = "ip -6 addr replace" + \
f" {intf_data['ipaddress']}/{intf_data['netmask']}" + \ f" {intf_data['ipaddress']}/{intf_data['netmask']}" + \
f" dev {intf} preferred_lft forever;" f" dev {intf} preferred_lft forever"
if constants.NETWORK_TYPE_MGMT in networktypelist: if constants.NETWORK_TYPE_MGMT in networktypelist:
fill_interface_config_option_operation(intf_data['options'], fill_interface_config_option_operation(intf_data['options'],
IFACE_POST_UP_OP, undeprecate) IFACE_POST_UP_OP, undeprecate)
@ -1794,13 +1689,11 @@ def generate_unassigned_pxeboot_intf_config(context, config, db_api,
if not is_pxeboot_present and is_mgmt_present: if not is_pxeboot_present and is_mgmt_present:
if mgmt_intf: if mgmt_intf:
LOG.info(f"add pxeboot network config in {mgmt_intf.ifname} ") LOG.info(f"add pxeboot network config in {mgmt_intf.ifname} ")
net_id = find_network_id_by_networktype(context, network = context['networks'][constants.NETWORK_TYPE_PXEBOOT]
constants.NETWORK_TYPE_PXEBOOT)
# Setup the default device configuration for the interface. This will be # Setup the default device configuration for the interface. This will be
# overridden if there is a specific network type configuration, otherwise # overridden if there is a specific network type configuration, otherwise
# it will act as the parent device for the aliases # it will act as the parent device for the aliases
mgmt_intf.networktypelist.append(constants.NETWORK_TYPE_PXEBOOT) mgmt_intf.networktypelist.append(constants.NETWORK_TYPE_PXEBOOT)
net_config = get_interface_network_config(context, mgmt_intf, net_id)
address_name = None address_name = None
if context['hostname'] == constants.CONTROLLER_0_HOSTNAME: if context['hostname'] == constants.CONTROLLER_0_HOSTNAME:
address_name = utils.format_address_name(constants.CONTROLLER_0_HOSTNAME, address_name = utils.format_address_name(constants.CONTROLLER_0_HOSTNAME,
@ -1808,15 +1701,12 @@ def generate_unassigned_pxeboot_intf_config(context, config, db_api,
elif context['hostname'] == constants.CONTROLLER_1_HOSTNAME: elif context['hostname'] == constants.CONTROLLER_1_HOSTNAME:
address_name = utils.format_address_name(constants.CONTROLLER_1_HOSTNAME, address_name = utils.format_address_name(constants.CONTROLLER_1_HOSTNAME,
constants.NETWORK_TYPE_PXEBOOT) constants.NETWORK_TYPE_PXEBOOT)
if address_name:
address = None address = None
if address_name:
address = utils.get_primary_address_by_name(db_api, address_name, address = utils.get_primary_address_by_name(db_api, address_name,
constants.NETWORK_TYPE_PXEBOOT) constants.NETWORK_TYPE_PXEBOOT)
if (address and net_config['method'] == 'static'):
addr_data = _set_address_netmask({'address': address.address, net_config = get_interface_network_config(context, mgmt_intf, network, address)
'prefix': address.prefix})
net_config['ipaddress'] = addr_data['address']
net_config['netmask'] = addr_data['netmask']
if net_config: if net_config:
config[NETWORK_CONFIG_RESOURCE].update({ config[NETWORK_CONFIG_RESOURCE].update({
@ -1824,11 +1714,22 @@ def generate_unassigned_pxeboot_intf_config(context, config, db_api,
}) })
def get_address_config(context, iface, address): def get_address_config(context, iface, addresses):
ifname = get_interface_os_ifname(context, iface) ifname = get_interface_os_ifname(context, iface)
if constants.DUAL_STACK_COMPATIBILITY_MODE:
address = addresses[0]
return { return {
'ifname': ifname, 'ifname': ifname,
'address': address, 'address': str(address.address) + '/' + str(address.prefix)
}
else:
address_list = []
for address in addresses:
address_list.append(str(address.address) + '/' + str(address.prefix))
return {
'ifname': ifname,
'addresses': address_list,
} }
@ -1836,10 +1737,10 @@ def generate_address_configs(context, config):
""" """
Generate the puppet resource for each of the floating IP addresses Generate the puppet resource for each of the floating IP addresses
""" """
for networktype, address in six.iteritems(context['floatingips']): for networktype, addresses in six.iteritems(context['floatingips']):
iface = find_interface_by_type(context, networktype) iface = find_interface_by_type(context, networktype)
if iface: if iface:
address_config = get_address_config(context, iface, address) address_config = get_address_config(context, iface, addresses)
config[ADDRESS_CONFIG_RESOURCE].update({ config[ADDRESS_CONFIG_RESOURCE].update({
networktype: address_config networktype: address_config
}) })
@ -1848,7 +1749,7 @@ def generate_address_configs(context, config):
iface = find_interface_by_type(context, iface = find_interface_by_type(context,
constants.NETWORK_TYPE_MGMT) constants.NETWORK_TYPE_MGMT)
if iface: if iface:
address_config = get_address_config(context, iface, address) address_config = get_address_config(context, iface, addresses)
config[ADDRESS_CONFIG_RESOURCE].update({ config[ADDRESS_CONFIG_RESOURCE].update({
networktype: address_config networktype: address_config
}) })
@ -1857,7 +1758,7 @@ def generate_address_configs(context, config):
iface = find_interface_by_type(context, iface = find_interface_by_type(context,
constants.NETWORK_TYPE_CLUSTER_HOST) constants.NETWORK_TYPE_CLUSTER_HOST)
if iface: if iface:
address_config = get_address_config(context, iface, address) address_config = get_address_config(context, iface, addresses)
config[ADDRESS_CONFIG_RESOURCE].update({ config[ADDRESS_CONFIG_RESOURCE].update({
networktype: address_config networktype: address_config
}) })
@ -1919,13 +1820,12 @@ def fill_interface_config_option_operation(options, operation, command):
""" """
Join new command to previous commands on the same operation Join new command to previous commands on the same operation
""" """
if_op = {IFACE_UP_OP: 'up', IFACE_PRE_UP_OP: 'pre_up', IFACE_POST_UP_OP: 'post_up', if_op = {IFACE_UP_OP: 'up',
IFACE_DOWN_OP: 'down', IFACE_PRE_DOWN_OP: 'pre_down', IFACE_POST_DOWN_OP: 'post_down'} IFACE_PRE_UP_OP: 'pre-up',
if not is_syscfg_network(): IFACE_POST_UP_OP: 'post-up',
if_op[IFACE_PRE_UP_OP] = 'pre-up' IFACE_DOWN_OP: 'down',
if_op[IFACE_POST_UP_OP] = 'post-up' IFACE_PRE_DOWN_OP: 'pre-down',
if_op[IFACE_PRE_DOWN_OP] = 'pre-down' IFACE_POST_DOWN_OP: 'post-down'}
if_op[IFACE_POST_DOWN_OP] = 'post-down'
if operation in if_op.keys(): if operation in if_op.keys():
if if_op[operation] in options.keys(): if if_op[operation] in options.keys():
@ -1937,21 +1837,11 @@ def fill_interface_config_option_operation(options, operation, command):
def get_intf_op_name(operation): def get_intf_op_name(operation):
if_op = {IFACE_UP_OP: 'up', IFACE_PRE_UP_OP: 'pre_up', IFACE_POST_UP_OP: 'post_up', if_op = {IFACE_UP_OP: 'up',
IFACE_DOWN_OP: 'down', IFACE_PRE_DOWN_OP: 'pre_down', IFACE_POST_DOWN_OP: 'post_down'} IFACE_PRE_UP_OP: 'pre-up',
if not is_syscfg_network(): IFACE_POST_UP_OP: 'post-up',
if_op[IFACE_PRE_UP_OP] = 'pre-up' IFACE_DOWN_OP: 'down',
if_op[IFACE_POST_UP_OP] = 'post-up' IFACE_PRE_DOWN_OP: 'pre-down',
if_op[IFACE_PRE_DOWN_OP] = 'pre-down' IFACE_POST_DOWN_OP: 'post-down'}
if_op[IFACE_POST_DOWN_OP] = 'post-down'
return if_op[operation] return if_op[operation]
def is_syscfg_network():
"""
Detect if the system is using sysconfig network interface file format
"""
if not os.path.isdir("/etc/sysconfig/network-scripts/"):
return False
return True

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)
network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=address_pool_id, for address_pool in address_pools:
network_id=network.id) network_addrpool = dbutils.create_test_network_addrpool(
address_pool_id=address_pool.id, network_id=network.id)
self.network_addrpools.append(network_addrpool) self.network_addrpools.append(network_addrpool)
self._add_address_pool_to_index(address_pool, network)
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,12 +453,21 @@ 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 subnet in subnets:
ips = itertools.islice(subnet, start, stop)
for name in hostnames: for name in hostnames:
address = dbutils.create_test_address( address = self._create_test_address(
name=utils.format_address_name(name, network_type), name=utils.format_address_name(name, network_type),
family=subnet.version, family=subnet.version,
prefix=subnet.prefixlen, prefix=subnet.prefixlen,
@ -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