Skip to content

Commit

Permalink
Restructure config to prepare for MAC address changes
Browse files Browse the repository at this point in the history
  • Loading branch information
erl-hpe committed Feb 21, 2025
1 parent d025bb7 commit 5ea2d4b
Show file tree
Hide file tree
Showing 4 changed files with 103 additions and 77 deletions.
20 changes: 11 additions & 9 deletions vtds_cluster_kvm/private/api_objects.py
Original file line number Diff line number Diff line change
Expand Up @@ -189,18 +189,20 @@ def __network_by_name(self, network_name):
)
return self.networks_by_name[network_name]

def __l3_config(self, network_name, family):
"""Get the l3_info block for the specified address family from
def __address_family(self, network_name, family):
"""Get the address_family block for the specified address family from
the network of the specified name. If the network doesn't
exist raise an exception. If there is no matching l3_info,
exist raise an exception. If there is no matching address_family,
return None.
"""
network = self.__network_by_name(network_name)
candidates = [
l3_info
for _, l3_info in network.get('l3_configs', {}).items()
if l3_info.get('family', None) == family
address_family
for _, address_family in network.get(
'address_families', {}
).items()
if address_family.get('family', None) == family
]
return candidates[0] if candidates else None

Expand All @@ -212,10 +214,10 @@ def application_metadata(self, network_name):
return network.get('application_metadata', {})

def ipv4_cidr(self, network_name):
l3_config = self.__l3_config(network_name, 'AF_INET')
if l3_config is None:
address_family = self.__address_family(network_name, 'AF_INET')
if address_family is None:
return None
return l3_config.get('cidr', None)
return address_family.get('cidr', None)

def non_cluster_network(self, network_name):
network = self.__network_by_name(network_name)
Expand Down
27 changes: 15 additions & 12 deletions vtds_cluster_kvm/private/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -190,21 +190,21 @@ def __net_name(network):
)
return netname

def __get_l3_config(self, network, family):
def __get_address_family(self, network, family):
"""Look up the L3 configuration for the specified address
family in the specified network.
"""
l3_configs = network.get('l3_configs', None)
if l3_configs is None:
address_families = network.get('address_families', None)
if address_families is None:
raise ContextualError(
"configuration error: network '%s' has no "
"'l3_configs' section" % self.__net_name(network)
"'address_families' section" % self.__net_name(network)
)
candidates = [
l3_config
for _, l3_config in l3_configs.items()
if l3_config.get('family', None) == family
address_family
for _, address_family in address_families.items()
if address_family.get('family', None) == family
]
if not candidates:
raise ContextualError(
Expand All @@ -223,8 +223,8 @@ def __get_ipv4_cidr(self, network):
there is none.
"""
l3_config = self.__get_l3_config(network, 'AF_INET')
cidr = l3_config.get('cidr', None)
address_family = self.__get_address_family(network, 'AF_INET')
cidr = address_family.get('cidr', None)
if cidr is None:
raise ContextualError(
"configuration error: AF_INET L3 configuration for "
Expand Down Expand Up @@ -272,8 +272,10 @@ def __add_host_blade_net(self):
)
# Connect the host_blade_network to all blades of all classes.
blade_classes = virtual_blades.blade_classes()
l3_config = self.__get_l3_config(host_blade_network, 'AF_INET')
l3_config['connected_blades'] = [
address_family = self.__get_address_family(
host_blade_network, 'AF_INET'
)
address_family['connected_blades'] = [
{
'blade_class': blade_class,
'blade_instances': [
Expand Down Expand Up @@ -343,7 +345,8 @@ def __random_mac(prefix="52:54:00"):
"""Generate a MAC address using a specified prefix specified
as a string containing colon separated hexadecimal octet
values for the length of the desired prefix. By default use
the KVM reserved prefix '52:54:00'.
the KVM reserved, locally administered, unicast prefix
'52:54:00'.
"""
try:
Expand Down
30 changes: 18 additions & 12 deletions vtds_cluster_kvm/private/config/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,22 @@ cluster:
# The name of the Blade Interconnect network underlying this
# Virtual Network. Set this to null for blade-local networks.
blade_interconnect: base-interconnect
l3_configs:
# Connected blades lists the blades that are connected to
# the Virtual Network (by default no blade is connected). If
# you are going to have a blade provided DHCP server on one
# of the blades for this network, that blade (class and
# instance) must be a connected blade. For a blade-local
# network to exist on a blade, that blade (class and
# instance) must be in the set of connected blades.
connected_blades:
# Connected blades are grouped by blade class and
# identified by instance numbers.
- blade_class: base-blade
blade_instances:
- 0
# Configuration for things that are specific to a given address
# family being used on the network.
address_families:
ipv4:
family: AF_INET
cidr: 10.254.0.0/16
Expand All @@ -126,19 +141,10 @@ cluster:
- 10.1.1.1
- 10.1.1.2
- 10.1.1.3
# Connected blades lists the blades that are connected to
# the Virtual Network (by default no blade is connected). If
# you are going to have a blade provided DHCP server on one
# of the blades for this network, that blade (class and
# instance) must be a connected blade. For a blade-local
# network to exist on a blade, that blade (class and
# instance) must be in the set of connected blades.
# Connected blades are assigned IP addresses by blade class
# which are indexed by instance number.
connected_blades:
# Connected blades are grouped by blade class and
# identified by instance numbers.
- blade_class: base-blade
blade_instances:
- 0
# Each connected blade instance is assigned an IP
# address on the Virtual Network using the following
# list of blade IPs matched one-to-one with blade
Expand Down
103 changes: 59 additions & 44 deletions vtds_cluster_kvm/private/scripts/deploy_cluster_to_blade.py
Original file line number Diff line number Diff line change
Expand Up @@ -247,29 +247,42 @@ def connected_blade_instances(network, blade_class):
network and blade class.
"""
l3_config = find_l3_config(network, 'AF_INET')
return [
int(blade_instance)
for blade in l3_config.get('connected_blades', [])
for blade in network.get('connected_blades', [])
if blade.get('blade_class', None) == blade_class
for blade_instance in blade.get('blade_instances', [])
]


def connected_blade_ipv4s(network, blade_class):
"""Get the list of conencted blade instance numbers for a given
"""Get the list of conencted blade IP addresses for a given
network and blade class.
"""
l3_config = find_l3_config(network, 'AF_INET')
address_family = find_address_family(network, 'AF_INET')
return [
ipv4_addr
for blade in l3_config.get('connected_blades', [])
for blade in address_family.get('connected_blades', [])
if blade.get('blade_class', None) == blade_class
for ipv4_addr in blade.get('blade_ips', [])
]


def connected_blade_macs(network, blade_class):
"""Get the list of conencted blade IP addresses for a given
network and blade class.
"""
address_family = find_address_family(network, 'AF_LINK')
return [
mac
for blade in address_family.get('connected_blades', [])
if blade.get('blade_class', None) == blade_class
for mac in blade.get('blade_macs', [])
]


def network_blade_connected(network, blade_class, blade_instance):
"""Determine whether the specified network is connected to the
specified instance of the specified blade class. If it is, return
Expand Down Expand Up @@ -300,7 +313,7 @@ def network_ipv4_gateway(network):
specified network. If no gateway is configured, return None.
"""
return find_l3_config(network, 'AF_INET').get('gateway', None)
return find_address_family(network, 'AF_INET').get('gateway', None)


def is_nat_router(network, blade_class, blade_instance):
Expand All @@ -322,10 +335,10 @@ def is_dhcp_server(network, blade_class, blade_instance):
hosts the gateway for that network).
"""
l3_config = find_l3_config(network, 'AF_INET')
address_family = find_address_family(network, 'AF_INET')
candidates = [
blade
for blade in l3_config.get('connected_blades', [])
for blade in address_family.get('connected_blades', [])
if blade.get('blade_class', None) == blade_class and
blade.get('dhcp_server_instance', None) == blade_instance
]
Expand Down Expand Up @@ -424,48 +437,50 @@ def find_addr_info(interface, family):
return addr_infos[0]


def find_l3_config(network, family):
def find_address_family(network, family):
"""Find the L3 configuration for the specified address family
('family') in the provided network configuration ('network').
"""
netname = net_name(network)
# There should be exactly one 'l3_config' block in the network
# There should be exactly one 'address_family' block in the network
# with the specified family.
l3_configs = [
l3_config
for _, l3_config in network.get('l3_configs', {}).items()
if l3_config.get('family', None) == family
address_families = [
address_family
for _, address_family in network.get('address_families', {}).items()
if address_family.get('family', None) == family
]
if len(l3_configs) > 1:
if len(address_families) > 1:
raise ContextualError(
"configuration error: the Virtual Network named '%s' has more "
"than one %s 'l3_config' block." % (netname, family)
"than one %s 'address_family' block." % (netname, family)
)
if not l3_configs:
if not address_families:
raise ContextualError(
"configuration error: the Virtual Network named '%s' has "
"no %s 'l3_config' block." % (netname, family)
"no %s 'address_family' block." % (netname, family)
)
return l3_configs[0]
return address_families[0]


def network_length(l3_config, netname):
"""Given an l3_config ('l3_config') from a network named 'netname'
return the network length from its 'cidr' element.
def network_length(address_family, netname):
"""Given an address_family ('address_family') from a network named
'netname' return the network length from its 'cidr' element.
"""
if 'cidr' not in l3_config:
if 'cidr' not in address_family:
raise ContextualError(
"configuration error: the AF_INET 'l3_config' block for the "
"configuration error: the AF_INET 'address_family' block for the "
"network named '%s' has no 'cidr' configured" % netname
)
if '/' not in l3_config['cidr']:
if '/' not in address_family['cidr']:
raise ContextualError(
"configuration error: the AF_INET 'cidr' value '%s' for the "
"network named '%s' is malformed" % (l3_config['cidr'], netname)
"network named '%s' is malformed" % (
address_family['cidr'], netname
)
)
return l3_config['cidr'].split('/')[1]
return address_family['cidr'].split('/')[1]


def find_blade_cidr(network, blade_class, blade_instance):
Expand All @@ -476,10 +491,10 @@ def find_blade_cidr(network, blade_class, blade_instance):
then return None.
"""
l3_config = find_l3_config(network, "AF_INET")
address_family = find_address_family(network, "AF_INET")
blade_ip = network_blade_ipv4(network, blade_class, blade_instance)
return (
'/'.join((blade_ip, network_length(l3_config, net_name(network))))
'/'.join((blade_ip, network_length(address_family, net_name(network))))
if blade_ip is not None else None
)

Expand Down Expand Up @@ -670,7 +685,7 @@ def install_nat_rule(network):
"""
dest_if = find_interconnect_interface()
cidr = find_l3_config(network, 'AF_INET')['cidr']
cidr = find_address_family(network, 'AF_INET')['cidr']
run_cmd(
'iptables',
[
Expand Down Expand Up @@ -1334,8 +1349,8 @@ def __make_network_interface(self, interface, network):
ipv4_info = find_addr_info(interface, "AF_INET")
mac_addrs = node_mac_addrs(interface)
addresses = ipv4_info.get('addresses', [])
l3_config = find_l3_config(network, "AF_INET")
net_length = network_length(l3_config, netname)
address_family = find_address_family(network, "AF_INET")
net_length = network_length(address_family, netname)
try:
mode = ipv4_info['mode']
except KeyError as err:
Expand Down Expand Up @@ -1617,21 +1632,21 @@ def __compose_reservations(self, interfaces):
]
return reservations

def __compose_subnet(self, blade_if, l3_config, interfaces):
def __compose_subnet(self, blade_if, address_family, interfaces):
"""Based on a network's l3 configuration block, compose the
DCP4 subnet configuration for Kea.
"""
pools = [
{'pool': "%s - %s" % (pool['start'], pool['end'])}
for pool in l3_config['dhcp'].get('pools', [])
for pool in address_family['dhcp'].get('pools', [])
]
try:
cidr = l3_config['cidr']
cidr = address_family['cidr']
except KeyError as err:
raise ContextualError(
"configuration error: network l3_config %s "
"has no 'cidr' element" % str(l3_config)
"configuration error: network address_family %s "
"has no 'cidr' element" % str(address_family)
) from err
subnet = {
'pools': pools,
Expand All @@ -1640,15 +1655,15 @@ def __compose_subnet(self, blade_if, l3_config, interfaces):
'reservations': self.__compose_reservations(interfaces),
'option-data': []
}
gateway = l3_config.get('gateway', None)
gateway = address_family.get('gateway', None)
if gateway:
subnet['option-data'].append(
{
'name': 'routers',
'data': gateway,
},
)
nameservers = l3_config.get('name_servers', [])
nameservers = address_family.get('name_servers', [])
if nameservers:
subnet['option-data'].append(
{
Expand All @@ -1661,8 +1676,8 @@ def __compose_subnet(self, blade_if, l3_config, interfaces):
def __compose_network(self, network):
"""Compose the base Kea DHCP4 configuration for the provided
network and return it. A network may be a set of subnets,
based on 'l3_config' blocks, so treat each AF_INET 'l3_config'
block as its own subnet.
based on 'address_family' blocks, so treat each AF_INET
'address_family' block as its own subnet.
"""
# Further filter network interfaces to get only those that
Expand All @@ -1673,10 +1688,10 @@ def __compose_network(self, network):
if if_network(interface) == net_name(network)
]
blade_if = blade_ipv4_ifname(network)
l3_config = find_l3_config(network, 'AF_INET')
address_family = find_address_family(network, 'AF_INET')
subnet = (
self.__compose_subnet(blade_if, l3_config, interfaces)
if l3_config.get('dhcp', {}) else None
self.__compose_subnet(blade_if, address_family, interfaces)
if address_family.get('dhcp', {}) else None
)
return [subnet] if subnet is not None else []

Expand Down

0 comments on commit 5ea2d4b

Please sign in to comment.