daemon: refactored usages of addr to ip and updated functions to align

This commit is contained in:
Blake Harnden 2020-06-19 10:54:58 -07:00
parent d88f3a2535
commit 20feea8f12
12 changed files with 138 additions and 118 deletions

View file

@ -29,7 +29,7 @@ class DefaultRouteService(ConfigService):
ifaces = self.node.get_ifaces() ifaces = self.node.get_ifaces()
if ifaces: if ifaces:
iface = ifaces[0] iface = ifaces[0]
for ip in iface.all_ips(): for ip in iface.ips():
net = ip.cidr net = ip.cidr
if net.size > 1: if net.size > 1:
router = net[1] router = net[1]
@ -76,7 +76,7 @@ class StaticRouteService(ConfigService):
def data(self) -> Dict[str, Any]: def data(self) -> Dict[str, Any]:
routes = [] routes = []
for iface in self.node.get_ifaces(control=False): for iface in self.node.get_ifaces(control=False):
for ip in iface.all_ips(): for ip in iface.ips():
address = str(ip.ip) address = str(ip.ip)
if netaddr.valid_ipv6(address): if netaddr.valid_ipv6(address):
dst = "3ffe:4::/64" dst = "3ffe:4::/64"

View file

@ -1548,7 +1548,7 @@ class Session:
entries = [] entries = []
for iface in control_net.get_ifaces(): for iface in control_net.get_ifaces():
name = iface.node.name name = iface.node.name
for ip in iface.all_ips(): for ip in iface.ips():
entries.append(f"{ip.ip} {name}") entries.append(f"{ip.ip} {name}")
logging.info("Adding %d /etc/hosts file entries.", len(entries)) logging.info("Adding %d /etc/hosts file entries.", len(entries))

View file

@ -7,7 +7,7 @@ import os
import shutil import shutil
import threading import threading
from threading import RLock from threading import RLock
from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type, Union from typing import TYPE_CHECKING, Dict, List, Optional, Tuple, Type, Union
import netaddr import netaddr
@ -138,6 +138,13 @@ class NodeBase(abc.ABC):
return self.position.get() return self.position.get()
def get_iface(self, iface_id: int) -> CoreInterface: def get_iface(self, iface_id: int) -> CoreInterface:
"""
Retrieve interface based on id.
:param iface_id: id of interface to retrieve
:return: interface
:raises CoreError: when interface does not exist
"""
if iface_id not in self.ifaces: if iface_id not in self.ifaces:
raise CoreError(f"node({self.name}) does not have interface({iface_id})") raise CoreError(f"node({self.name}) does not have interface({iface_id})")
return self.ifaces[iface_id] return self.ifaces[iface_id]
@ -436,7 +443,6 @@ class CoreNode(CoreNodeBase):
""" """
apitype: NodeTypes = NodeTypes.DEFAULT apitype: NodeTypes = NodeTypes.DEFAULT
valid_address_types: Set[str] = {"inet", "inet6", "inet6link"}
def __init__( def __init__(
self, self,
@ -750,40 +756,39 @@ class CoreNode(CoreNodeBase):
if self.up: if self.up:
self.node_net_client.device_mac(iface.name, mac) self.node_net_client.device_mac(iface.name, mac)
def addaddr(self, iface_id: int, addr: str) -> None: def add_ip(self, iface_id: int, ip: str) -> None:
""" """
Add interface address. Add an ip address to an interface in the format "10.0.0.1/24".
:param iface_id: id of interface to add address to :param iface_id: id of interface to add address to
:param addr: address to add to interface :param ip: address to add to interface
:return: nothing
"""
addr = utils.validate_ip(addr)
iface = self.get_iface(iface_id)
iface.addaddr(addr)
if self.up:
# ipv4 check
broadcast = None
if netaddr.valid_ipv4(addr):
broadcast = "+"
self.node_net_client.create_address(iface.name, addr, broadcast)
def deladdr(self, iface_id: int, addr: str) -> None:
"""
Delete address from an interface.
:param iface_id: id of interface to delete address from
:param addr: address to delete from interface
:return: nothing :return: nothing
:raises CoreError: when ip address provided is invalid
:raises CoreCommandError: when a non-zero exit status occurs :raises CoreCommandError: when a non-zero exit status occurs
""" """
iface = self.get_iface(iface_id) iface = self.get_iface(iface_id)
try: iface.add_ip(ip)
iface.deladdr(addr)
except ValueError:
logging.exception("trying to delete unknown address: %s", addr)
if self.up: if self.up:
self.node_net_client.delete_address(iface.name, addr) # ipv4 check
broadcast = None
if netaddr.valid_ipv4(ip):
broadcast = "+"
self.node_net_client.create_address(iface.name, ip, broadcast)
def remove_ip(self, iface_id: int, ip: str) -> None:
"""
Remove an ip address from an interface in the format "10.0.0.1/24".
:param iface_id: id of interface to delete address from
:param ip: ip address to remove from interface
:return: nothing
:raises CoreError: when ip address provided is invalid
:raises CoreCommandError: when a non-zero exit status occurs
"""
iface = self.get_iface(iface_id)
iface.remove_ip(ip)
if self.up:
self.node_net_client.delete_address(iface.name, ip)
def ifup(self, iface_id: int) -> None: def ifup(self, iface_id: int) -> None:
""" """
@ -819,14 +824,14 @@ class CoreNode(CoreNodeBase):
iface = self.get_iface(iface_id) iface = self.get_iface(iface_id)
iface.set_mac(iface_data.mac) iface.set_mac(iface_data.mac)
for address in addresses: for address in addresses:
iface.addaddr(address) iface.add_ip(address)
else: else:
iface_id = self.newveth(iface_data.id, iface_data.name) iface_id = self.newveth(iface_data.id, iface_data.name)
self.attachnet(iface_id, net) self.attachnet(iface_id, net)
if iface_data.mac: if iface_data.mac:
self.set_mac(iface_id, iface_data.mac) self.set_mac(iface_id, iface_data.mac)
for address in addresses: for address in addresses:
self.addaddr(iface_id, address) self.add_ip(iface_id, address)
self.ifup(iface_id) self.ifup(iface_id)
iface = self.get_iface(iface_id) iface = self.get_iface(iface_id)
return iface return iface

View file

@ -134,46 +134,64 @@ class CoreInterface:
if self.net is not None: if self.net is not None:
self.net.detach(self) self.net.detach(self)
def addaddr(self, address: str) -> None: def add_ip(self, ip: str) -> None:
""" """
Add ip address in the format "10.0.0.1/24". Add ip address in the format "10.0.0.1/24".
:param address: address to add :param ip: ip address to add
:return: nothing :return: nothing
:raises CoreError: when ip address provided is invalid
""" """
try: try:
ip = netaddr.IPNetwork(address) ip = netaddr.IPNetwork(ip)
value = str(ip.ip) address = str(ip.ip)
if netaddr.valid_ipv4(value): if netaddr.valid_ipv4(address):
self.ip4s.append(ip) self.ip4s.append(ip)
else: else:
self.ip6s.append(ip) self.ip6s.append(ip)
except netaddr.AddrFormatError: except netaddr.AddrFormatError:
raise CoreError(f"adding invalid address {address}") raise CoreError(f"adding invalid address {ip}")
def deladdr(self, addr: str) -> None: def remove_ip(self, ip: str) -> None:
""" """
Delete address. Remove ip address in the format "10.0.0.1/24".
:param addr: address to delete :param ip: ip address to delete
:return: nothing :return: nothing
:raises CoreError: when ip address provided is invalid
""" """
if netaddr.valid_ipv4(addr): try:
ip4 = netaddr.IPNetwork(addr) ip = netaddr.IPNetwork(ip)
self.ip4s.remove(ip4) address = str(ip.ip)
elif netaddr.valid_ipv6(addr): if netaddr.valid_ipv4(address):
ip6 = netaddr.IPNetwork(addr) self.ip4s.remove(ip)
self.ip6s.remove(ip6) else:
else: self.ip6s.remove(ip)
raise CoreError(f"deleting invalid address {addr}") except (netaddr.AddrFormatError, ValueError):
raise CoreError(f"deleting invalid address {ip}")
def get_ip4(self) -> Optional[netaddr.IPNetwork]: def get_ip4(self) -> Optional[netaddr.IPNetwork]:
"""
Looks for the first ip4 address.
:return: ip4 address, None otherwise
"""
return next(iter(self.ip4s), None) return next(iter(self.ip4s), None)
def get_ip6(self) -> Optional[netaddr.IPNetwork]: def get_ip6(self) -> Optional[netaddr.IPNetwork]:
"""
Looks for the first ip6 address.
:return: ip6 address, None otherwise
"""
return next(iter(self.ip6s), None) return next(iter(self.ip6s), None)
def all_ips(self) -> List[netaddr.IPNetwork]: def ips(self) -> List[netaddr.IPNetwork]:
"""
Retrieve a list of all ip4 and ip6 addresses combined.
:return: ip4 and ip6 addresses
"""
return self.ip4s + self.ip6s return self.ip4s + self.ip6s
def set_mac(self, mac: str) -> None: def set_mac(self, mac: str) -> None:
@ -518,7 +536,7 @@ class TunTap(CoreInterface):
:return: nothing :return: nothing
""" """
self.waitfordevicenode() self.waitfordevicenode()
for ip in self.all_ips(): for ip in self.ips():
self.node.node_net_client.create_address(self.name, str(ip)) self.node.node_net_client.create_address(self.name, str(ip))

View file

@ -575,18 +575,17 @@ class CoreNetwork(CoreNetworkBase):
return iface return iface
return None return None
def addrconfig(self, addrlist: List[str]) -> None: def add_ips(self, ips: List[str]) -> None:
""" """
Set addresses on the bridge. Add ip addresses on the bridge in the format "10.0.0.1/24".
:param addrlist: address list :param ips: ip address to add
:return: nothing :return: nothing
""" """
if not self.up: if not self.up:
return return
for ip in ips:
for addr in addrlist: self.net_client.create_address(self.brname, ip)
self.net_client.create_address(self.brname, str(addr))
class GreTapBridge(CoreNetwork): class GreTapBridge(CoreNetwork):
@ -663,22 +662,22 @@ class GreTapBridge(CoreNetwork):
self.gretap = None self.gretap = None
super().shutdown() super().shutdown()
def addrconfig(self, addrlist: List[str]) -> None: def add_ips(self, ips: List[str]) -> None:
""" """
Set the remote tunnel endpoint. This is a one-time method for Set the remote tunnel endpoint. This is a one-time method for
creating the GreTap device, which requires the remoteip at startup. creating the GreTap device, which requires the remoteip at startup.
The 1st address in the provided list is remoteip, 2nd optionally The 1st address in the provided list is remoteip, 2nd optionally
specifies localip. specifies localip.
:param addrlist: address list :param ips: address list
:return: nothing :return: nothing
""" """
if self.gretap: if self.gretap:
raise ValueError(f"gretap already exists for {self.name}") raise ValueError(f"gretap already exists for {self.name}")
remoteip = addrlist[0].split("/")[0] remoteip = ips[0].split("/")[0]
localip = None localip = None
if len(addrlist) > 1: if len(ips) > 1:
localip = addrlist[1].split("/")[0] localip = ips[1].split("/")[0]
self.gretap = GreTap( self.gretap = GreTap(
session=self.session, session=self.session,
remoteip=remoteip, remoteip=remoteip,
@ -700,7 +699,7 @@ class GreTapBridge(CoreNetwork):
self.grekey = key self.grekey = key
addresses = iface_data.get_addresses() addresses = iface_data.get_addresses()
if addresses: if addresses:
self.addrconfig(addresses) self.add_ips(addresses)
class CtrlNet(CoreNetwork): class CtrlNet(CoreNetwork):

View file

@ -75,43 +75,43 @@ class PhysicalNode(CoreNodeBase):
:raises CoreCommandError: when a non-zero exit status occurs :raises CoreCommandError: when a non-zero exit status occurs
""" """
mac = utils.validate_mac(mac) mac = utils.validate_mac(mac)
iface = self.ifaces[iface_id] iface = self.get_iface(iface_id)
iface.set_mac(mac) iface.set_mac(mac)
if self.up: if self.up:
self.net_client.device_mac(iface.name, mac) self.net_client.device_mac(iface.name, mac)
def addaddr(self, iface_id: int, addr: str) -> None: def add_ip(self, iface_id: int, ip: str) -> None:
""" """
Add an address to an interface. Add an ip address to an interface in the format "10.0.0.1/24".
:param iface_id: index of interface to add address to :param iface_id: id of interface to add address to
:param addr: address to add :param ip: address to add to interface
:return: nothing :return: nothing
:raises CoreError: when ip address provided is invalid
:raises CoreCommandError: when a non-zero exit status occurs
""" """
addr = utils.validate_ip(addr)
iface = self.get_iface(iface_id) iface = self.get_iface(iface_id)
iface.add_ip(ip)
if self.up: if self.up:
self.net_client.create_address(iface.name, addr) self.net_client.create_address(iface.name, ip)
iface.addaddr(addr)
def deladdr(self, iface_id: int, addr: str) -> None: def remove_ip(self, iface_id: int, ip: str) -> None:
""" """
Delete an address from an interface. Remove an ip address from an interface in the format "10.0.0.1/24".
:param iface_id: index of interface to delete :param iface_id: id of interface to delete address from
:param addr: address to delete :param ip: ip address to remove from interface
:return: nothing :return: nothing
:raises CoreError: when ip address provided is invalid
:raises CoreCommandError: when a non-zero exit status occurs
""" """
iface = self.ifaces[iface_id] iface = self.get_iface(iface_id)
try: iface.remove_ip(ip)
iface.deladdr(addr)
except ValueError:
logging.exception("trying to delete unknown address: %s", addr)
if self.up: if self.up:
self.net_client.delete_address(iface.name, addr) self.net_client.delete_address(iface.name, ip)
def adopt_iface( def adopt_iface(
self, iface: CoreInterface, iface_id: int, mac: str, addrlist: List[str] self, iface: CoreInterface, iface_id: int, mac: str, ips: List[str]
) -> None: ) -> None:
""" """
When a link message is received linking this node to another part of When a link message is received linking this node to another part of
@ -128,8 +128,8 @@ class PhysicalNode(CoreNodeBase):
iface.localname = iface.name iface.localname = iface.name
if mac: if mac:
self.set_mac(iface_id, mac) self.set_mac(iface_id, mac)
for addr in addrlist: for ip in ips:
self.addaddr(iface_id, addr) self.add_ip(iface_id, ip)
if self.up: if self.up:
self.net_client.device_up(iface.localname) self.net_client.device_up(iface.localname)
@ -317,7 +317,7 @@ class Rj45Node(CoreNodeBase):
if net is not None: if net is not None:
self.iface.attachnet(net) self.iface.attachnet(net)
for addr in iface_data.get_addresses(): for addr in iface_data.get_addresses():
self.addaddr(addr) self.add_ip(addr)
return self.iface return self.iface
def delete_iface(self, iface_id: int) -> None: def delete_iface(self, iface_id: int) -> None:
@ -348,30 +348,31 @@ class Rj45Node(CoreNodeBase):
raise CoreError(f"node({self.name}) does not have interface({iface.name})") raise CoreError(f"node({self.name}) does not have interface({iface.name})")
return self.iface_id return self.iface_id
def addaddr(self, addr: str) -> None: def add_ip(self, ip: str) -> None:
""" """
Add address to to network interface. Add an ip address to an interface in the format "10.0.0.1/24".
:param addr: address to add :param ip: address to add to interface
:return: nothing :return: nothing
:raises CoreCommandError: when there is a command exception :raises CoreError: when ip address provided is invalid
:raises CoreCommandError: when a non-zero exit status occurs
""" """
addr = utils.validate_ip(addr) self.iface.add_ip(ip)
if self.up: if self.up:
self.net_client.create_address(self.name, addr) self.net_client.create_address(self.name, ip)
self.iface.addaddr(addr)
def deladdr(self, addr: str) -> None: def remove_ip(self, ip: str) -> None:
""" """
Delete address from network interface. Remove an ip address from an interface in the format "10.0.0.1/24".
:param addr: address to delete :param ip: ip address to remove from interface
:return: nothing :return: nothing
:raises CoreCommandError: when there is a command exception :raises CoreError: when ip address provided is invalid
:raises CoreCommandError: when a non-zero exit status occurs
""" """
self.iface.remove_ip(ip)
if self.up: if self.up:
self.net_client.delete_address(self.name, addr) self.net_client.delete_address(self.name, ip)
self.iface.deladdr(addr)
def savestate(self) -> None: def savestate(self) -> None:
""" """

View file

@ -67,7 +67,7 @@ class FRRZebra(CoreService):
# include control interfaces in addressing but not routing daemons # include control interfaces in addressing but not routing daemons
if hasattr(iface, "control") and iface.control is True: if hasattr(iface, "control") and iface.control is True:
cfg += " " cfg += " "
cfg += "\n ".join(map(cls.addrstr, iface.all_ips())) cfg += "\n ".join(map(cls.addrstr, iface.ips()))
cfg += "\n" cfg += "\n"
continue continue
cfgv4 = "" cfgv4 = ""

View file

@ -64,7 +64,7 @@ class Zebra(CoreService):
# include control interfaces in addressing but not routing daemons # include control interfaces in addressing but not routing daemons
if getattr(iface, "control", False): if getattr(iface, "control", False):
cfg += " " cfg += " "
cfg += "\n ".join(map(cls.addrstr, iface.all_ips())) cfg += "\n ".join(map(cls.addrstr, iface.ips()))
cfg += "\n" cfg += "\n"
continue continue
cfgv4 = "" cfgv4 = ""

View file

@ -74,7 +74,7 @@ class DefaultRouteService(UtilService):
ifaces = node.get_ifaces() ifaces = node.get_ifaces()
if ifaces: if ifaces:
iface = ifaces[0] iface = ifaces[0]
for ip in iface.all_ips(): for ip in iface.ips():
net = ip.cidr net = ip.cidr
if net.size > 1: if net.size > 1:
router = net[1] router = net[1]
@ -118,7 +118,7 @@ class StaticRouteService(UtilService):
cfg += "# NOTE: this service must be customized to be of any use\n" cfg += "# NOTE: this service must be customized to be of any use\n"
cfg += "# Below are samples that you can uncomment and edit.\n#\n" cfg += "# Below are samples that you can uncomment and edit.\n#\n"
for iface in node.get_ifaces(control=False): for iface in node.get_ifaces(control=False):
cfg += "\n".join(map(cls.routestr, iface.all_ips())) cfg += "\n".join(map(cls.routestr, iface.ips()))
cfg += "\n" cfg += "\n"
return cfg return cfg
@ -241,7 +241,7 @@ max-lease-time 7200;
ddns-update-style none; ddns-update-style none;
""" """
for iface in node.get_ifaces(control=False): for iface in node.get_ifaces(control=False):
cfg += "\n".join(map(cls.subnetentry, iface.all_ips())) cfg += "\n".join(map(cls.subnetentry, iface.ips()))
cfg += "\n" cfg += "\n"
return cfg return cfg
@ -555,10 +555,7 @@ export LANG
% node.name % node.name
) )
for iface in node.get_ifaces(control=False): for iface in node.get_ifaces(control=False):
body += "<li>%s - %s</li>\n" % ( body += "<li>%s - %s</li>\n" % (iface.name, [str(x) for x in iface.ips()])
iface.name,
[str(x) for x in iface.all_ips()],
)
return "<html><body>%s</body></html>" % body return "<html><body>%s</body></html>" % body
@ -626,7 +623,7 @@ class RadvdService(UtilService):
""" """
cfg = "# auto-generated by RADVD service (utility.py)\n" cfg = "# auto-generated by RADVD service (utility.py)\n"
for iface in node.get_ifaces(control=False): for iface in node.get_ifaces(control=False):
prefixes = list(map(cls.subnetentry, iface.all_ips())) prefixes = list(map(cls.subnetentry, iface.ips()))
if len(prefixes) < 1: if len(prefixes) < 1:
continue continue
cfg += ( cfg += (

View file

@ -40,7 +40,7 @@ class XorpRtrmgr(CoreService):
for iface in node.get_ifaces(): for iface in node.get_ifaces():
cfg += " interface %s {\n" % iface.name cfg += " interface %s {\n" % iface.name
cfg += "\tvif %s {\n" % iface.name cfg += "\tvif %s {\n" % iface.name
cfg += "".join(map(cls.addrstr, iface.all_ips())) cfg += "".join(map(cls.addrstr, iface.ips()))
cfg += cls.lladdrstr(iface) cfg += cls.lladdrstr(iface)
cfg += "\t}\n" cfg += "\t}\n"
cfg += " }\n" cfg += " }\n"

View file

@ -164,7 +164,7 @@ class CoreXmlDeployment:
if emane_element is not None: if emane_element is not None:
parent_element = emane_element parent_element = emane_element
for ip in iface.all_ips(): for ip in iface.ips():
address = str(ip.ip) address = str(ip.ip)
address_type = get_address_type(address) address_type = get_address_type(address)
add_address(parent_element, address_type, address, iface.name) add_address(parent_element, address_type, address, iface.name)

View file

@ -75,31 +75,31 @@ class TestNodes:
with pytest.raises(CoreError): with pytest.raises(CoreError):
node.set_mac(iface.node_id, mac) node.set_mac(iface.node_id, mac)
def test_node_addaddr(self, session: Session): def test_node_add_ip(self, session: Session):
# given # given
node = session.add_node(CoreNode) node = session.add_node(CoreNode)
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
iface_data = InterfaceData() iface_data = InterfaceData()
iface = node.new_iface(switch, iface_data) iface = node.new_iface(switch, iface_data)
addr = "192.168.0.1/24" ip = "192.168.0.1/24"
# when # when
node.addaddr(iface.node_id, addr) node.add_ip(iface.node_id, ip)
# then # then
assert str(iface.get_ip4()) == addr assert str(iface.get_ip4()) == ip
def test_node_addaddr_exception(self, session): def test_node_add_ip_exception(self, session):
# given # given
node = session.add_node(CoreNode) node = session.add_node(CoreNode)
switch = session.add_node(SwitchNode) switch = session.add_node(SwitchNode)
iface_data = InterfaceData() iface_data = InterfaceData()
iface = node.new_iface(switch, iface_data) iface = node.new_iface(switch, iface_data)
addr = "256.168.0.1/24" ip = "256.168.0.1/24"
# when # when
with pytest.raises(CoreError): with pytest.raises(CoreError):
node.addaddr(iface.node_id, addr) node.add_ip(iface.node_id, ip)
@pytest.mark.parametrize("net_type", NET_TYPES) @pytest.mark.parametrize("net_type", NET_TYPES)
def test_net(self, session, net_type): def test_net(self, session, net_type):