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
# 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.
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.
OAM_ADDRESS_POOL = 'oam'
SYSTEM_CONTROLLER_OAM_ADDRESS_POOL = 'system-controller-oam-subnet'
if constants.DUAL_STACK_COMPATIBILITY_MODE:
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
# is allowed to be deleted/modified post install
MANAGEMENT_ADDRESS_POOL = 'management'
AIOSX_WRITABLE_ADDRPOOLS = [MANAGEMENT_ADDRESS_POOL]
if constants.DUAL_STACK_COMPATIBILITY_MODE:
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):
@ -324,8 +335,8 @@ class AddressPoolController(rest.RestController):
f"{addrpool['prefix']}"])
pools = pecan.request.dbapi.address_pools_get_all()
for pool in pools:
if pool.name == OAM_ADDRESS_POOL and \
addrpool['name'] == SYSTEM_CONTROLLER_OAM_ADDRESS_POOL:
if pool.name in OAM_ADDRESS_POOL_OVERLAP_INDEX and \
addrpool['name'] == OAM_ADDRESS_POOL_OVERLAP_INDEX[pool.name]:
# we are ignoring overlap in this case as subcloud oam and
# system-controller oam are sharable.
continue
@ -405,15 +416,15 @@ class AddressPoolController(rest.RestController):
any(network.type == constants.NETWORK_TYPE_MGMT
for network in networks):
if (new_name != MANAGEMENT_ADDRESS_POOL):
if (new_name != addrpool.name):
msg = _("Cannot complete the action because the "
"address pool for mgmt network must be named as '{}'."
.format(MANAGEMENT_ADDRESS_POOL))
.format(addrpool.name))
raise ValueError(msg)
def _check_aiosx_mgmt(self, addrpool):
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() !=
constants.DISTRIBUTED_CLOUD_ROLE_SUBCLOUD):
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
# from the no_proxy list
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)
# 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'.
if pool_uuid:
pool = pecan.request.dbapi.address_pool_get(pool_uuid)
if pool['name'] != "management":
msg = _("Network of type {} must use the addrpool named '{}'."
.format(networktype, address_pool.MANAGEMENT_ADDRESS_POOL))
if constants.DUAL_STACK_COMPATIBILITY_MODE:
pool_name = address_pool.MANAGEMENT_ADDRESS_POOL_NAMES[None]
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)
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_ENABLED = 'enabled'
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.")
class AddressNotFoundById(NotFound):
message = _("Address %(address_id)s could not be found.")
class AddressNotFoundByAddress(NotFound):
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,
sort_key=None, sort_dir=None):
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,
sort_key, sort_dir, query)
@ -5384,6 +5386,16 @@ class Connection(api.Connection):
raise exception.AddressNotFound(address_uuid=address_uuid)
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):
query = model_query(models.Addresses)
query = (query.
@ -5412,6 +5424,10 @@ class Connection(api.Connection):
def address_get(self, 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)
def address_get_by_name(self, name, limit=None, marker=None,
sort_key=None, sort_dir=None):

View File

@ -6,7 +6,6 @@
import collections
import copy
import os
import re
import six
@ -129,6 +128,10 @@ class InterfacePuppet(base.BasePuppet):
def _create_interface_context(self, host):
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 = {
'hostname': host.hostname,
'personality': host.personality,
@ -137,14 +140,17 @@ class InterfacePuppet(base.BasePuppet):
'system_mode': self._get_system().system_mode,
'ports': self._get_port_interface_id_index(host),
'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(
host.hostname, host_interfaces),
'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),
'networks': self._get_network_type_index(),
'gateways': self._get_gateway_index(),
'floatingips': self._get_floating_ip_index(),
'networks': networks,
'address_pools': address_pools,
'floatingips': self._get_floating_ip_index(networks, address_pools,
network_address_pools),
'datanets': self._get_datanetworks(host),
'vswitchtype': self._vswitch_type(),
}
@ -196,6 +202,61 @@ class InterfacePuppet(base.BasePuppet):
"""
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):
"""
Builds a dictionary of route lists indexed by interface name.
@ -216,118 +277,55 @@ class InterfacePuppet(base.BasePuppet):
networks[network['type']] = network
return networks
def _get_gateway_index(self):
"""
Builds a dictionary of gateway IP addresses indexed by network type.
"""
gateways = {}
try:
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
def _get_address_pool_index(self):
addrpool_index = {}
addrpools = self.dbapi.address_pools_get_all()
for addrpool in addrpools:
addrpool_index[addrpool.uuid] = addrpool
return addrpool_index
try:
oam_address = self._get_address_by_name(
constants.CONTROLLER_GATEWAY, constants.NETWORK_TYPE_OAM)
gateways.update({
constants.NETWORK_TYPE_OAM: oam_address.address})
except exception.AddressNotFoundByName:
pass
def _get_network_addresspool_index(self):
network_addrpool_index = {}
network_addrpools = self.dbapi.network_addrpool_get_all()
for network_addrpool in network_addrpools:
network_addrpool_index[network_addrpool.address_pool_uuid] = network_addrpool
return network_addrpool_index
return gateways
def _get_floating_ip_index(self):
def _get_floating_ip_index(self, networks, address_pools, network_address_pools):
"""
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) + '/' +
str(mgmt_address.prefix))
floating_ips = {
constants.NETWORK_TYPE_MGMT: mgmt_floating_ip
}
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
networktypes = [
constants.NETWORK_TYPE_MGMT,
constants.NETWORK_TYPE_PXEBOOT,
constants.NETWORK_TYPE_CLUSTER_HOST,
constants.NETWORK_TYPE_IRONIC,
constants.NETWORK_TYPE_STORAGE,
constants.NETWORK_TYPE_ADMIN
]
system = self._get_system()
if system.system_mode != constants.SYSTEM_MODE_SIMPLEX:
oam_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME, constants.NETWORK_TYPE_OAM)
networktypes.append(constants.NETWORK_TYPE_OAM)
oam_floating_ip = (str(oam_address.address) + '/' +
str(oam_address.prefix))
floating_ips.update({
constants.NETWORK_TYPE_OAM: oam_floating_ip
})
network_index = {}
for network in networks.values():
if network.type in networktypes:
network_index[network.id] = network
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:
cluster_address = self._get_address_by_name(
constants.CONTROLLER_HOSTNAME,
constants.NETWORK_TYPE_CLUSTER_HOST)
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:
address = self.dbapi.address_get_by_id(address_pool.floating_address_id)
floating_ips[network.type].append(address)
except exception.AddressNotFoundById:
pass
return floating_ips
@ -666,82 +664,46 @@ def _set_address_netmask(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
addresses exist then the first address is returned.
Gets the corresponding gateway for the provided address
"""
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):
"""
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:
if not addrpool:
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):
"""
Determine what type of interface to configure for each network type.
"""
networktype = find_networktype_by_network_id(context, network_id)
def get_interface_address_method(context, iface, network=None, address=None):
networktype = network.type if network else None
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
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:
return STATIC_METHOD
# All data interfaces configured in the kernel because they are not
# natively supported in vswitch or need to be shared with the kernel
# because of a platform VLAN should be left as manual config
return MANUAL_METHOD
elif (iface.ifclass == constants.INTERFACE_CLASS_PLATFORM and
networktype is None and 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
elif (iface.ifclass == constants.INTERFACE_CLASS_PLATFORM and networktype is None):
if has_static_addr:
return STATIC_METHOD
return MANUAL_METHOD
elif not iface.ifclass or iface.ifclass == constants.INTERFACE_CLASS_NONE \
or not networktype:
# Interfaces that are configured purely as a dependency from other
@ -871,42 +833,21 @@ def get_basic_network_config(ifname, ensure='present',
'onboot': onboot,
'options': {}}
if mtu:
if is_syscfg_network():
config['mtu'] = str(mtu)
else:
config['options']['mtu'] = str(mtu)
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
def is_disable_dad_required(context, iface, config, network_id=None):
"""
Determine whether DAD is required to be disabled.
If mgmt and cluster-host are separate vlans, the vlan has DAD disabled.
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]):
if network:
return False
networks = [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_CLUSTER_HOST]
for networktype in iface.networktypelist:
if networktype in networks:
return True
return False
@ -922,21 +863,18 @@ def get_interface_sysctl_ifname(context, iface):
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
"""
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; "
"grep %s /sys/class/net/bonding_masters || "
"echo +%s > /sys/class/net/bonding_masters" % (
iface['ifname'], iface['ifname']))
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'])
sysctl_ifname = get_interface_sysctl_ifname(context, iface)
@ -951,9 +889,6 @@ def get_vlan_network_config(context, iface, config):
interface.
"""
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}
fill_interface_config_option_operation(options, IFACE_PRE_UP_OP,
'/sbin/modprobe -q 8021q')
@ -976,28 +911,6 @@ def add_vlan_interface_creation_command(context, iface, options):
'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):
"""
Get the interface config attribute for bonding options
@ -1028,7 +941,7 @@ def get_bond_interface_options_ifupdown(iface, primary_iface):
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
interface.
@ -1038,12 +951,6 @@ def get_bond_network_config(context, iface, config, network_id):
bonding_options = None
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
bonding_options = get_bond_interface_options_ifupdown(iface, primary_iface)
if bonding_options:
@ -1092,14 +999,9 @@ def get_ethernet_network_config(context, iface, config):
"""
interface_class = iface['ifclass']
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_syscfg_network():
options['BRIDGE'] = get_bridge_interface_name(context, iface)
pass
elif is_slave_interface(context, iface):
if not is_data_interface(context, iface):
# 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
# on the device (e.g., the Mellanox DPDK driver relies on the
# 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)
options['bond-master'] = master
osname = get_interface_os_ifname(context, iface)
@ -1346,13 +1243,11 @@ def get_fpga_config(context, iface):
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
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)
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,
traffic_classifier)
method = get_interface_address_method(context, iface, network_id)
method = get_interface_address_method(context, iface, network, address)
if method == STATIC_METHOD:
address = get_interface_primary_address(context, iface, network_id)
if address:
_set_address_netmask(address)
config['ipaddress'] = address['address']
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_interface_gateway_address(context, networktype)
gateway = get_gateway_address(context, network, address)
if gateway:
if is_syscfg_network():
config['gateway'] = gateway
else:
config['options']['gateway'] = gateway
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
appended to an attribute that is already configured (e.g. pre_up)
"""
# add duplex_direct specific network config
if context['system_mode'] == constants.SYSTEM_MODE_DUPLEX_DIRECT:
if is_disable_dad_required(context, iface, config, network_id):
config = get_duplex_direct_network_config(context, iface, config,
network_id)
if is_disable_dad_required(iface, network):
config = get_duplex_direct_network_config(context, iface, config, network)
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
"""
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 {}
# Create a basic network config resource
os_ifname = get_interface_os_ifname(context, iface)
method = get_interface_address_method(context, iface, network_id)
family = get_interface_address_family(context, iface, network_id)
family = get_address_family(address)
# for now label all interfaces that have network_id, later we will
# set the definitive values
if network_id:
ifname = "%s:%d" % (os_ifname, network_id)
if network or address:
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:
ifname = os_ifname
@ -1419,13 +1312,10 @@ def get_interface_network_config(context, iface, network_id=None):
ifname, method=method, family=family, mtu=mtu)
# 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
if os_ifname == LOOPBACK_IFNAME:
if is_syscfg_network():
options = {'SCOPE': 'scope host'}
else:
options = {'scope': 'host'}
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:
config = get_vlan_network_config(context, iface, config)
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:
config = get_ethernet_network_config(context, iface, config)
# 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:
# When configuring a static IPv6 interface, CentOS' ifup tool uses 'ip link'
# 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)
# disable ipv6 autoconfig
if is_syscfg_network():
config['options'].update({'IPV6_AUTOCONF': 'no'})
else:
interface_op = IFACE_POST_UP_OP
if is_slave_interface(context, iface):
# 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)
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
if not is_syscfg_network():
networktype = find_networktype_by_network_id(context, network_id)
config['options']['stx-description'] = f"ifname:{iface['ifname']},net:{networktype}"
config['options']['stx-description'] = f"ifname:{iface['ifname']},net:{network_type}"
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):
"""
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
bridge, or to add additional route resources.
"""
os_ifname = get_interface_os_ifname(context, iface)
# Setup the default device configuration for the interface. This will be
# overridden if there is a specific network type configuration, otherwise
# it will act as the parent device for the aliases
net_config = get_interface_network_config(context, iface)
if net_config:
hiera_config[NETWORK_CONFIG_RESOURCE].update({
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)
})
networks = context['interface_networks'][iface.ifname]
for network_dict in networks.values():
net_configs = get_interface_network_configs(context, iface, network_dict['network'])
for net_config in net_configs:
hiera_config[NETWORK_CONFIG_RESOURCE][net_config['ifname']] = \
format_network_config(net_config)
# Add complementary puppet resource definitions (if needed)
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):
for net_type, network in six.iteritems(context['networks']):
if networktype == net_type:
network = context['networks'].get(networktype, None)
if network:
return network.id
def find_networktype_by_network_id(context, network_id):
for networktype, network in six.iteritems(context['networks']):
if network.id == network_id:
return networktype
return None
def find_interface_by_type(context, networktype):
@ -1555,20 +1465,6 @@ def find_interface_by_type(context, networktype):
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):
"""
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
requirements
"""
# This rules are a result of using Debian's ifupdown package,
# StarlingX do not support dual-stack for now
# This rules are a result of using Debian's ifupdown package
#
# Rules for label adjustment:
# 1) if the interface have just one label:
@ -1700,7 +1595,7 @@ def process_interface_labels(config, context):
networktypelist = context['interfaces'][ifname].networktypelist
undeprecate = "ip -6 addr replace" + \
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:
fill_interface_config_option_operation(intf_data['options'],
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 mgmt_intf:
LOG.info(f"add pxeboot network config in {mgmt_intf.ifname} ")
net_id = find_network_id_by_networktype(context,
constants.NETWORK_TYPE_PXEBOOT)
network = context['networks'][constants.NETWORK_TYPE_PXEBOOT]
# Setup the default device configuration for the interface. This will be
# overridden if there is a specific network type configuration, otherwise
# it will act as the parent device for the aliases
mgmt_intf.networktypelist.append(constants.NETWORK_TYPE_PXEBOOT)
net_config = get_interface_network_config(context, mgmt_intf, net_id)
address_name = None
if context['hostname'] == 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:
address_name = utils.format_address_name(constants.CONTROLLER_1_HOSTNAME,
constants.NETWORK_TYPE_PXEBOOT)
if address_name:
address = None
if address_name:
address = utils.get_primary_address_by_name(db_api, address_name,
constants.NETWORK_TYPE_PXEBOOT)
if (address and net_config['method'] == 'static'):
addr_data = _set_address_netmask({'address': address.address,
'prefix': address.prefix})
net_config['ipaddress'] = addr_data['address']
net_config['netmask'] = addr_data['netmask']
net_config = get_interface_network_config(context, mgmt_intf, network, address)
if net_config:
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)
if constants.DUAL_STACK_COMPATIBILITY_MODE:
address = addresses[0]
return {
'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
"""
for networktype, address in six.iteritems(context['floatingips']):
for networktype, addresses in six.iteritems(context['floatingips']):
iface = find_interface_by_type(context, networktype)
if iface:
address_config = get_address_config(context, iface, address)
address_config = get_address_config(context, iface, addresses)
config[ADDRESS_CONFIG_RESOURCE].update({
networktype: address_config
})
@ -1848,7 +1749,7 @@ def generate_address_configs(context, config):
iface = find_interface_by_type(context,
constants.NETWORK_TYPE_MGMT)
if iface:
address_config = get_address_config(context, iface, address)
address_config = get_address_config(context, iface, addresses)
config[ADDRESS_CONFIG_RESOURCE].update({
networktype: address_config
})
@ -1857,7 +1758,7 @@ def generate_address_configs(context, config):
iface = find_interface_by_type(context,
constants.NETWORK_TYPE_CLUSTER_HOST)
if iface:
address_config = get_address_config(context, iface, address)
address_config = get_address_config(context, iface, addresses)
config[ADDRESS_CONFIG_RESOURCE].update({
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
"""
if_op = {IFACE_UP_OP: 'up', IFACE_PRE_UP_OP: 'pre_up', IFACE_POST_UP_OP: 'post_up',
IFACE_DOWN_OP: 'down', IFACE_PRE_DOWN_OP: 'pre_down', IFACE_POST_DOWN_OP: 'post_down'}
if not is_syscfg_network():
if_op[IFACE_PRE_UP_OP] = 'pre-up'
if_op[IFACE_POST_UP_OP] = 'post-up'
if_op[IFACE_PRE_DOWN_OP] = 'pre-down'
if_op[IFACE_POST_DOWN_OP] = 'post-down'
if_op = {IFACE_UP_OP: 'up',
IFACE_PRE_UP_OP: 'pre-up',
IFACE_POST_UP_OP: 'post-up',
IFACE_DOWN_OP: 'down',
IFACE_PRE_DOWN_OP: 'pre-down',
IFACE_POST_DOWN_OP: 'post-down'}
if operation in if_op.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):
if_op = {IFACE_UP_OP: 'up', IFACE_PRE_UP_OP: 'pre_up', IFACE_POST_UP_OP: 'post_up',
IFACE_DOWN_OP: 'down', IFACE_PRE_DOWN_OP: 'pre_down', IFACE_POST_DOWN_OP: 'post_down'}
if not is_syscfg_network():
if_op[IFACE_PRE_UP_OP] = 'pre-up'
if_op[IFACE_POST_UP_OP] = 'post-up'
if_op[IFACE_PRE_DOWN_OP] = 'pre-down'
if_op[IFACE_POST_DOWN_OP] = 'post-down'
if_op = {IFACE_UP_OP: 'up',
IFACE_PRE_UP_OP: 'pre-up',
IFACE_POST_UP_OP: 'post-up',
IFACE_DOWN_OP: 'down',
IFACE_PRE_DOWN_OP: 'pre-down',
IFACE_POST_DOWN_OP: 'post-down'}
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
#
@ -88,7 +88,7 @@ class AddressPoolTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
def _delete_management_pool(self):
current_pools = self.get_json(self.API_PREFIX)
for addrpool in current_pools[self.RESULT_KEY]:
if addrpool['name'] == 'management':
if addrpool['name'].startswith('management'):
uuid = addrpool['uuid']
self.delete(self.get_single_url(uuid),
headers=self.API_HEADERS)
@ -178,12 +178,14 @@ class TestPostMixin(AddressPoolTestCase):
f"with {name_1} address pool.",
response.json['error_message'])
def _test_create_address_pool_pass_overlap_with_oam(self, network,
prefix):
name = "system-controller-oam-subnet"
def _test_create_address_pool_pass_overlap_with_oam(self, network, prefix):
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
name_1 = f"{name}_1"
name_1 = f"{sysctl_oam_pool_name}_1"
ndict_1 = self.get_post_object(name_1, network, prefix)
response = self.post_json(self.API_PREFIX,
ndict_1,
@ -194,11 +196,11 @@ class TestPostMixin(AddressPoolTestCase):
self.assertEqual('application/json', response.content_type)
self.assertEqual(response.status_code, http_client.CONFLICT)
self.assertIn(f"Address pool {network}/{prefix} overlaps "
f"with oam address pool.",
f"with {oam_pool_name} address pool.",
response.json['error_message'])
# 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,
ndict_2,
headers=self.API_HEADERS)
@ -422,7 +424,11 @@ class TestPostMixin(AddressPoolTestCase):
network = str(self.mgmt_subnet.network)
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])
response = self.post_json(self.API_PREFIX,

View File

@ -2,7 +2,7 @@
# -*- 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
#
@ -556,11 +556,6 @@ class InterfaceTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
if key in second:
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):
for pool in self.address_pools:
if pool['uuid'] == pool_uuid:

View File

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

View File

@ -111,8 +111,6 @@ class NetworkAddrpoolTestCase(base.FunctionalTest, dbbase.BaseHostTestCase):
return network
def _setup_context(self):
print("_setup_context")
self.host0 = self._create_test_host(personality=constants.CONTROLLER, unit=0,
id=1, mgmt_ip="1.1.1.1")
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
net_type = constants.NETWORK_TYPE_MGMT
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,
ndict,
headers=self.API_HEADERS)
@ -159,9 +157,12 @@ class TestPostMixin(NetworkAddrpoolTestCase):
self.assertEqual('application/json', response.content_type)
self.assertEqual(response.status_code, http_client.OK)
# Check that an expected field matches.
self.assertEqual(response.json['address_pool_name'], self.address_pools['management'].name)
self.assertEqual(response.json['address_pool_id'], self.address_pools['management'].id)
self.assertEqual(response.json['address_pool_uuid'], self.address_pools['management'].uuid)
self.assertEqual(response.json['address_pool_name'],
self.address_pools['management-ipv4'].name)
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_id'], self.networks[net_type].id)
self.assertEqual(response.json['network_uuid'], self.networks[net_type].uuid)
@ -169,9 +170,9 @@ class TestPostMixin(NetworkAddrpoolTestCase):
uuid = response.json['uuid']
# Verify that the object was created and some basic attribute matches
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_id'], self.address_pools['management'].id)
self.assertEqual(response['address_pool_uuid'], self.address_pools['management'].uuid)
self.assertEqual(response['address_pool_name'], self.address_pools['management-ipv4'].name)
self.assertEqual(response['address_pool_id'], self.address_pools['management-ipv4'].id)
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_id'], self.networks[net_type].id)
self.assertEqual(response['network_uuid'], self.networks[net_type].uuid)
@ -195,7 +196,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary
net_type = constants.NETWORK_TYPE_MGMT
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,
ndict,
headers=self.API_HEADERS)
@ -252,7 +253,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary
net_type = constants.NETWORK_TYPE_OAM
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,
ndict,
headers=self.API_HEADERS)
@ -367,7 +368,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary
net_type = constants.NETWORK_TYPE_MGMT
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,
ndict,
headers=self.API_HEADERS)
@ -377,7 +378,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add secondary
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,
ndict,
headers=self.API_HEADERS,
@ -390,7 +391,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary
net_type = constants.NETWORK_TYPE_PXEBOOT
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,
ndict,
headers=self.API_HEADERS)
@ -413,7 +414,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
# add primary
net_type = constants.NETWORK_TYPE_MGMT
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,
ndict,
headers=self.API_HEADERS)
@ -445,7 +446,7 @@ class TestPostMixin(NetworkAddrpoolTestCase):
def test_error_create_network_addrpool_primary_duplicate(self):
net_type = constants.NETWORK_TYPE_MGMT
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,
ndict,
headers=self.API_HEADERS)
@ -486,7 +487,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_MGMT
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)
response = self.delete(self.get_single_url(net_pool.uuid),
@ -507,7 +508,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_MGMT
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)
response = self.delete(self.get_single_url(net_pool.uuid),
@ -528,7 +529,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_MGMT
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)
net_pool_2 = dbutils.create_test_network_addrpool(
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
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['primary_pool_family'],
self.networks[net_type].primary_pool_family)
@ -568,7 +569,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_OAM
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)
response = self.delete(self.get_single_url(net_pool.uuid),
@ -589,7 +590,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_PXEBOOT
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)
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_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)
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_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)
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_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)
response = self.delete(self.get_single_url(net_pool.uuid),
@ -673,7 +674,7 @@ class TestDelete(NetworkAddrpoolTestCase):
net_type = constants.NETWORK_TYPE_STORAGE
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)
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
#
@ -204,6 +204,15 @@ class TestPatchMixin(OAMNetworkTestCase):
self._test_patch_success(patch_obj)
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
patch_obj = {
'oam_floating_ip': str(oam_floating_ip),

View File

@ -17,7 +17,7 @@
# License for the specific language governing permissions and limitations
# under the License.
#
# Copyright (c) 2013-2023 Wind River Systems, Inc.
# Copyright (c) 2013-2024 Wind River Systems, Inc.
#
"""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)
pool_mgmt6 = self.dbapi.address_pool_query({"name": "management-ipv6"})
pool_mgmt4 = self.dbapi.address_pool_query({"name": "management"})
dbutils.create_test_network_addrpool(address_pool_id=pool_mgmt6.id, network_id=net_mgmt.id)
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)
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_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host"})
dbutils.create_test_network_addrpool(address_pool_id=pool_clhost6.id, network_id=net_clhost.id)
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)
worker_name = 'newhost'
ihost['mgmt_mac'] = '00:11:22:33:44:55'
@ -5972,8 +5974,8 @@ class ManagerTestCaseInternal(base.BaseHostTestCase):
self.create_ipv6_pools()
pool_mgmt4 = self.dbapi.address_pool_query({"name": "management"})
pool_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host"})
pool_mgmt4 = self.dbapi.address_pool_query({"name": "management-ipv4"})
pool_clhost4 = self.dbapi.address_pool_query({"name": "cluster-host-ipv4"})
net_pools = self.dbapi.network_addrpool_get_all()
for net_pool in net_pools:
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
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)
class DbTestCase(base.TestCase):
@ -49,19 +76,34 @@ class DbTestCase(base.TestCase):
class BaseIPv4Mixin(object):
pxeboot_subnet = netaddr.IPNetwork('192.168.202.0/24')
mgmt_subnet = netaddr.IPNetwork('192.168.204.0/24')
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')
primary_address_family = constants.IPV4_FAMILY
secondary_address_family = None
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
change_family_oam_subnet = netaddr.IPNetwork('fd00::/64')
@ -69,24 +111,77 @@ class BaseIPv4Mixin(object):
class BaseIPv6Mixin(object):
pxeboot_subnet = netaddr.IPNetwork('192.168.202.0/24')
mgmt_subnet = netaddr.IPNetwork('fd01::/64')
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')
primary_address_family = constants.IPV6_FAMILY
secondary_address_family = None
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
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):
def setUp(self):
@ -135,7 +230,10 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
super(BaseSystemTestCase, self).setUp()
self.hosts = []
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.datanetworks = []
self._create_test_common()
@ -152,7 +250,9 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self.ptp = None
self.hosts = []
self.address_pools = []
self.networks = []
self.networks_by_type = {}
self.networks_by_id = {}
self.address_pools_by_network_id = {}
self.network_addrpools = []
self.datanetworks = []
self.oam = None
@ -208,27 +308,50 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self.ptp = dbutils.create_test_ptp(
system_id=self.system.id)
def _create_test_network(self, name, network_type, subnet, ranges=None):
address_pool_id = self._create_test_address_pool(name, subnet, ranges).id
def _format_pool_name(self, network_name, subnet):
if subnet.version == constants.IPV6_FAMILY:
family = 'ipv6'
else:
family = 'ipv4'
return network_name + '-' + family
primary_pool_family = ""
if not isinstance(subnet, netaddr.IPNetwork):
subnet = netaddr.IPNetwork(subnet)
def _create_test_network(self, name, network_type, subnets, link_addresses=False):
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(
type=network_type,
address_pool_id=address_pool_id,
address_pool_id=address_pools[0].id,
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,
network_id=network.id)
for address_pool in address_pools:
network_addrpool = dbutils.create_test_network_addrpool(
address_pool_id=address_pool.id, network_id=network.id)
self.network_addrpools.append(network_addrpool)
self._add_address_pool_to_index(address_pool, network)
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):
route = dbutils.create_test_route(
interface_id=interface.id,
@ -245,16 +368,20 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self.datanetworks.append(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:
ranges = [(str(subnet[2]), str(subnet[-2]))]
base_address = netaddr.IPAddress(subnet[1])
gateway_address = None
floating_address = None
controller0_address = None
controller1_address = None
if name in ["pxeboot", "management", "oam", "cluster-host", "storage", "admin"]:
floating_address = netaddr.IPAddress(ranges[0][0])
controller0_address = floating_address + 1
controller1_address = floating_address + 2
if link_addresses:
gateway_address = base_address
floating_address = base_address + 1
controller0_address = base_address + 2
controller1_address = base_address + 3
pool = dbutils.create_test_address_pool(
name=name,
@ -262,6 +389,7 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
family=subnet.version,
prefix=subnet.prefixlen,
ranges=ranges,
gateway_address=str(gateway_address),
floating_address=str(floating_address),
controller0_address=str(controller0_address),
controller1_address=str(controller1_address))
@ -273,43 +401,49 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self._create_test_network('pxeboot',
constants.NETWORK_TYPE_PXEBOOT,
self.pxeboot_subnet)
self.pxeboot_subnets,
link_addresses=True)
self._create_test_network('management',
constants.NETWORK_TYPE_MGMT,
self.mgmt_subnet)
self.mgmt_subnets,
link_addresses=True)
self._create_test_network('oam',
constants.NETWORK_TYPE_OAM,
self.oam_subnet)
self.oam_subnets,
link_addresses=True)
self._create_test_network('cluster-host',
constants.NETWORK_TYPE_CLUSTER_HOST,
self.cluster_host_subnet)
self.cluster_host_subnets,
link_addresses=True)
self._create_test_network('cluster-pod',
constants.NETWORK_TYPE_CLUSTER_POD,
self.cluster_pod_subnet)
self.cluster_pod_subnets)
self._create_test_network('cluster-service',
constants.NETWORK_TYPE_CLUSTER_SERVICE,
self.cluster_service_subnet)
self.cluster_service_subnets)
self._create_test_network('storage',
constants.NETWORK_TYPE_STORAGE,
self.storage_subnet)
self.storage_subnets,
link_addresses=True)
self._create_test_network('admin',
constants.NETWORK_TYPE_ADMIN,
self.admin_subnet)
self.admin_subnets,
link_addresses=True)
self._create_test_network('system-controller',
constants.NETWORK_TYPE_SYSTEM_CONTROLLER,
self.system_controller_subnet)
self.system_controller_subnets)
self._create_test_network('system-controller-oam',
constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM,
self.system_controller_oam_subnet)
self.system_controller_oam_subnets)
def _create_test_datanetworks(self):
@ -319,12 +453,21 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
self._create_test_datanetwork('data1',
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):
ips = itertools.islice(subnet, start, stop)
addresses = []
for subnet in subnets:
ips = itertools.islice(subnet, start, stop)
for name in hostnames:
address = dbutils.create_test_address(
address = self._create_test_address(
name=utils.format_address_name(name, network_type),
family=subnet.version,
prefix=subnet.prefixlen,
@ -341,36 +484,35 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
]
self._create_test_addresses(
hostnames, self.pxeboot_subnet,
hostnames, self.pxeboot_subnets,
constants.NETWORK_TYPE_PXEBOOT)
self.mgmt_addresses = self._create_test_addresses(
hostnames,
self.mgmt_subnet,
hostnames, self.mgmt_subnets,
constants.NETWORK_TYPE_MGMT)
self._create_test_addresses(
hostnames, self.oam_subnet,
hostnames, self.oam_subnets,
constants.NETWORK_TYPE_OAM)
self._create_test_addresses(
hostnames, self.cluster_host_subnet,
hostnames, self.cluster_host_subnets,
constants.NETWORK_TYPE_CLUSTER_HOST)
self._create_test_addresses(
hostnames, self.storage_subnet,
hostnames, self.storage_subnets,
constants.NETWORK_TYPE_STORAGE)
self._create_test_addresses(
hostnames, self.admin_subnet,
hostnames, self.admin_subnets,
constants.NETWORK_TYPE_ADMIN)
self._create_test_addresses(
hostnames, self.system_controller_subnet,
hostnames, self.system_controller_subnets,
constants.NETWORK_TYPE_SYSTEM_CONTROLLER)
self._create_test_addresses(
hostnames, self.system_controller_oam_subnet,
hostnames, self.system_controller_oam_subnets,
constants.NETWORK_TYPE_SYSTEM_CONTROLLER_OAM)
def _create_test_oam(self):
@ -386,9 +528,24 @@ class BaseSystemTestCase(BaseIPv4Mixin, DbTestCase):
]
self._create_test_addresses(
hostnames, self.multicast_subnet,
hostnames, self.multicast_subnets,
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)
class BaseHostTestCase(BaseSystemTestCase):
@ -484,10 +641,10 @@ class BaseHostTestCase(BaseSystemTestCase):
def _create_test_host_addresses(self, hostname):
self._create_test_addresses(
[hostname], self.mgmt_subnet,
[hostname], self.mgmt_subnets,
constants.NETWORK_TYPE_MGMT, start=10)
self._create_test_addresses(
[hostname], self.cluster_host_subnet,
[hostname], self.cluster_host_subnets,
constants.NETWORK_TYPE_CLUSTER_HOST, start=10)
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_data_interface(self.host2)
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()

View File

@ -62,13 +62,14 @@ class DbNetworkTestCaseIPv4(base.BaseHostTestCase):
def test_network_addrpool_db(self):
to_add = [
(constants.NETWORK_TYPE_MGMT, ('management', 'management-ipv6')),
(constants.NETWORK_TYPE_OAM, ('oam', 'oam-ipv6')),
(constants.NETWORK_TYPE_ADMIN, ('admin', 'admin-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_HOST, ('cluster-host', 'cluster-host-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_POD, ('cluster-pod', 'cluster-pod-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_SERVICE, ('cluster-service', 'cluster-service-ipv6')),
(constants.NETWORK_TYPE_STORAGE, ('storage', 'storage-ipv6'))
(constants.NETWORK_TYPE_MGMT, ('management-ipv4', 'management-ipv6')),
(constants.NETWORK_TYPE_OAM, ('oam-ipv4', 'oam-ipv6')),
(constants.NETWORK_TYPE_ADMIN, ('admin-ipv4', 'admin-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_HOST, ('cluster-host-ipv4', 'cluster-host-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_POD, ('cluster-pod-ipv4', 'cluster-pod-ipv6')),
(constants.NETWORK_TYPE_CLUSTER_SERVICE, ('cluster-service-ipv4',
'cluster-service-ipv6')),
(constants.NETWORK_TYPE_STORAGE, ('storage-ipv4', 'storage-ipv6'))
]
# test network_addrpool_create()
@ -101,16 +102,16 @@ class DbNetworkTestCaseIPv4(base.BaseHostTestCase):
net_pools = self.dbapi.network_addrpool_get_by_network_id(net.id)
self.assertEqual(len(net_pools), 2)
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].address_pool_name, "management-ipv6")
# 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)
self.assertEqual(len(net_pools), 1)
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()
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)
self._create_test_addresses(hostnames=[constants.CONTROLLER_HOSTNAME],
subnet=netaddr.IPNetwork('fd01::/64'),
subnets=[netaddr.IPNetwork('fd01::/64')],
network_type=constants.NETWORK_TYPE_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)
gateway_address = address_pool.pop('gateway_address', None)
addresses = []
if floating_address:
try:
fl_addr = dbapi.address_get_by_address(floating_address)
addresses.append(fl_addr)
address_pool['floating_address_id'] = fl_addr.id
except Exception:
pass
if controller0_address:
try:
c0_addr = dbapi.address_get_by_address(controller0_address)
addresses.append(c0_addr)
address_pool['controller0_address_id'] = c0_addr.id
except Exception:
pass
if controller1_address:
try:
c1_addr = dbapi.address_get_by_address(controller1_address)
addresses.append(c1_addr)
address_pool['controller1_address_id'] = c1_addr.id
except Exception:
pass
if gateway_address:
try:
c1_addr = dbapi.address_get_by_address(gateway_address)
address_pool['gateway_address_id'] = c1_addr.id
gw_addr = dbapi.address_get_by_address(gateway_address)
addresses.append(gw_addr)
address_pool['gateway_address_id'] = gw_addr.id
except Exception:
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):
@ -1363,6 +1371,18 @@ def create_test_interface(**kw):
forihostid = kw.get('forihostid')
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
for network in networks_list:
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__
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):
if isinstance(networktype, list):
networktypelist = networktype
@ -259,11 +254,11 @@ class NetworkingTestTestCaseControllerDualStackIPv4Primary(NetworkingTestCaseMix
subnet=cfgdata[1][0])
network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=pool.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)
if cfgdata[0] in [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM]:
self._create_test_addresses(hostnames=[constants.CONTROLLER_GATEWAY],
subnet=cfgdata[1][0],
subnets=[cfgdata[1][0]],
network_type=cfgdata[0], start=1, stop=2)
self.network_addrpools.append(network_addrpool)
@ -398,11 +393,11 @@ class NetworkingTestTestCaseControllerDualStackIPv6Primary(NetworkingTestCaseMix
subnet=cfgdata[1][0])
network_addrpool = dbutils.create_test_network_addrpool(address_pool_id=pool.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)
if cfgdata[0] in [constants.NETWORK_TYPE_MGMT, constants.NETWORK_TYPE_OAM]:
self._create_test_addresses(hostnames=[constants.CONTROLLER_GATEWAY],
subnet=cfgdata[1][0],
subnets=[cfgdata[1][0]],
network_type=cfgdata[0], start=1, stop=2)
self.network_addrpools.append(network_addrpool)

View File

@ -61,11 +61,6 @@ class PlatformFirewallTestCaseMixin(base.PuppetTestCaseMixin):
def _setup_configuration(self):
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):
if isinstance(networktype, list):
networktypelist = networktype

View File

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