daemon: added type hinting throughout all services and made small tweaks/fixes that were ran across

This commit is contained in:
Blake Harnden 2020-06-18 12:54:36 -07:00
parent 250bc6e1f5
commit cd74a44558
11 changed files with 560 additions and 636 deletions

View file

@ -1,12 +1,13 @@
"""
utility.py: defines miscellaneous utility services.
"""
import os
from typing import Optional, Tuple
import netaddr
from core import constants, utils
from core.errors import CoreCommandError
from core.nodes.base import CoreNode
from core.services.coreservices import CoreService, ServiceMode
@ -15,32 +16,25 @@ class UtilService(CoreService):
Parent class for utility services.
"""
name = None
group = "Utility"
dirs = ()
configs = ()
startup = ()
shutdown = ()
name: Optional[str] = None
group: str = "Utility"
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
return ""
class IPForwardService(UtilService):
name = "IPForward"
configs = ("ipforward.sh",)
startup = ("sh ipforward.sh",)
name: str = "IPForward"
configs: Tuple[str, ...] = ("ipforward.sh",)
startup: Tuple[str, ...] = ("sh ipforward.sh",)
@classmethod
def generate_config(cls, node, filename):
if os.uname()[0] == "Linux":
return cls.generateconfiglinux(node, filename)
else:
raise Exception("unknown platform")
def generate_config(cls, node: CoreNode, filename: str) -> str:
return cls.generateconfiglinux(node, filename)
@classmethod
def generateconfiglinux(cls, node, filename):
def generateconfiglinux(cls, node: CoreNode, filename: str) -> str:
cfg = """\
#!/bin/sh
# auto-generated by IPForward service (utility.py)
@ -70,12 +64,12 @@ class IPForwardService(UtilService):
class DefaultRouteService(UtilService):
name = "DefaultRoute"
configs = ("defaultroute.sh",)
startup = ("sh defaultroute.sh",)
name: str = "DefaultRoute"
configs: Tuple[str, ...] = ("defaultroute.sh",)
startup: Tuple[str, ...] = ("sh defaultroute.sh",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
routes = []
ifaces = node.get_ifaces()
if ifaces:
@ -93,22 +87,18 @@ class DefaultRouteService(UtilService):
class DefaultMulticastRouteService(UtilService):
name = "DefaultMulticastRoute"
configs = ("defaultmroute.sh",)
startup = ("sh defaultmroute.sh",)
name: str = "DefaultMulticastRoute"
configs: Tuple[str, ...] = ("defaultmroute.sh",)
startup: Tuple[str, ...] = ("sh defaultmroute.sh",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by DefaultMulticastRoute service (utility.py)\n"
cfg += "# the first interface is chosen below; please change it "
cfg += "as needed\n"
for iface in node.get_ifaces(control=False):
if os.uname()[0] == "Linux":
rtcmd = "ip route add 224.0.0.0/4 dev"
else:
raise Exception("unknown platform")
rtcmd = "ip route add 224.0.0.0/4 dev"
cfg += "%s %s\n" % (rtcmd, iface.name)
cfg += "\n"
break
@ -116,13 +106,13 @@ class DefaultMulticastRouteService(UtilService):
class StaticRouteService(UtilService):
name = "StaticRoute"
configs = ("staticroute.sh",)
startup = ("sh staticroute.sh",)
custom_needed = True
name: str = "StaticRoute"
configs: Tuple[str, ...] = ("staticroute.sh",)
startup: Tuple[str, ...] = ("sh staticroute.sh",)
custom_needed: bool = True
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
cfg = "#!/bin/sh\n"
cfg += "# auto-generated by StaticRoute service (utility.py)\n#\n"
cfg += "# NOTE: this service must be customized to be of any use\n"
@ -133,7 +123,7 @@ class StaticRouteService(UtilService):
return cfg
@staticmethod
def routestr(x):
def routestr(x: str) -> str:
addr = x.split("/")[0]
if netaddr.valid_ipv6(addr):
dst = "3ffe:4::/64"
@ -143,24 +133,20 @@ class StaticRouteService(UtilService):
if net[-2] == net[1]:
return ""
else:
if os.uname()[0] == "Linux":
rtcmd = "#/sbin/ip route add %s via" % dst
else:
raise Exception("unknown platform")
rtcmd = "#/sbin/ip route add %s via" % dst
return "%s %s" % (rtcmd, net[1])
class SshService(UtilService):
name = "SSH"
configs = ("startsshd.sh", "/etc/ssh/sshd_config")
dirs = ("/etc/ssh", "/var/run/sshd")
startup = ("sh startsshd.sh",)
shutdown = ("killall sshd",)
validate = ()
validation_mode = ServiceMode.BLOCKING
name: str = "SSH"
configs: Tuple[str, ...] = ("startsshd.sh", "/etc/ssh/sshd_config")
dirs: Tuple[str, ...] = ("/etc/ssh", "/var/run/sshd")
startup: Tuple[str, ...] = ("sh startsshd.sh",)
shutdown: Tuple[str, ...] = ("killall sshd",)
validation_mode: ServiceMode = ServiceMode.BLOCKING
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Use a startup script for launching sshd in order to wait for host
key generation.
@ -228,15 +214,15 @@ UseDNS no
class DhcpService(UtilService):
name = "DHCP"
configs = ("/etc/dhcp/dhcpd.conf",)
dirs = ("/etc/dhcp", "/var/lib/dhcp")
startup = ("touch /var/lib/dhcp/dhcpd.leases", "dhcpd")
shutdown = ("killall dhcpd",)
validate = ("pidof dhcpd",)
name: str = "DHCP"
configs: Tuple[str, ...] = ("/etc/dhcp/dhcpd.conf",)
dirs: Tuple[str, ...] = ("/etc/dhcp", "/var/lib/dhcp")
startup: Tuple[str, ...] = ("touch /var/lib/dhcp/dhcpd.leases", "dhcpd")
shutdown: Tuple[str, ...] = ("killall dhcpd",)
validate: Tuple[str, ...] = ("pidof dhcpd",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a dhcpd config file using the network address of
each interface.
@ -261,7 +247,7 @@ ddns-update-style none;
return cfg
@staticmethod
def subnetentry(x):
def subnetentry(x: str) -> str:
"""
Generate a subnet declaration block given an IPv4 prefix string
for inclusion in the dhcpd3 config file.
@ -297,14 +283,14 @@ class DhcpClientService(UtilService):
Use a DHCP client for all interfaces for addressing.
"""
name = "DHCPClient"
configs = ("startdhcpclient.sh",)
startup = ("sh startdhcpclient.sh",)
shutdown = ("killall dhclient",)
validate = ("pidof dhclient",)
name: str = "DHCPClient"
configs: Tuple[str, ...] = ("startdhcpclient.sh",)
startup: Tuple[str, ...] = ("sh startdhcpclient.sh",)
shutdown: Tuple[str, ...] = ("killall dhclient",)
validate: Tuple[str, ...] = ("pidof dhclient",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a script to invoke dhclient on all interfaces.
"""
@ -313,7 +299,6 @@ class DhcpClientService(UtilService):
cfg += "# uncomment this mkdir line and symlink line to enable client-"
cfg += "side DNS\n# resolution based on the DHCP server response.\n"
cfg += "#mkdir -p /var/run/resolvconf/interface\n"
for iface in node.get_ifaces(control=False):
cfg += "#ln -s /var/run/resolvconf/interface/%s.dhclient" % iface.name
cfg += " /var/run/resolvconf/resolv.conf\n"
@ -327,15 +312,15 @@ class FtpService(UtilService):
Start a vsftpd server.
"""
name = "FTP"
configs = ("vsftpd.conf",)
dirs = ("/var/run/vsftpd/empty", "/var/ftp")
startup = ("vsftpd ./vsftpd.conf",)
shutdown = ("killall vsftpd",)
validate = ("pidof vsftpd",)
name: str = "FTP"
configs: Tuple[str, ...] = ("vsftpd.conf",)
dirs: Tuple[str, ...] = ("/var/run/vsftpd/empty", "/var/ftp")
startup: Tuple[str, ...] = ("vsftpd ./vsftpd.conf",)
shutdown: Tuple[str, ...] = ("killall vsftpd",)
validate: Tuple[str, ...] = ("pidof vsftpd",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a vsftpd.conf configuration file.
"""
@ -360,13 +345,13 @@ class HttpService(UtilService):
Start an apache server.
"""
name = "HTTP"
configs = (
name: str = "HTTP"
configs: Tuple[str, ...] = (
"/etc/apache2/apache2.conf",
"/etc/apache2/envvars",
"/var/www/index.html",
)
dirs = (
dirs: Tuple[str, ...] = (
"/etc/apache2",
"/var/run/apache2",
"/var/log/apache2",
@ -374,14 +359,14 @@ class HttpService(UtilService):
"/var/lock/apache2",
"/var/www",
)
startup = ("chown www-data /var/lock/apache2", "apache2ctl start")
shutdown = ("apache2ctl stop",)
validate = ("pidof apache2",)
APACHEVER22, APACHEVER24 = (22, 24)
startup: Tuple[str, ...] = ("chown www-data /var/lock/apache2", "apache2ctl start")
shutdown: Tuple[str, ...] = ("apache2ctl stop",)
validate: Tuple[str, ...] = ("pidof apache2",)
APACHEVER22: int = 22
APACHEVER24: int = 24
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate an apache2.conf configuration file.
"""
@ -395,7 +380,7 @@ class HttpService(UtilService):
return ""
@classmethod
def detectversionfromcmd(cls):
def detectversionfromcmd(cls) -> int:
"""
Detect the apache2 version using the 'a2query' command.
"""
@ -405,14 +390,12 @@ class HttpService(UtilService):
except CoreCommandError as e:
status = e.returncode
result = e.stderr
if status == 0 and result[:3] == "2.4":
return cls.APACHEVER24
return cls.APACHEVER22
@classmethod
def generateapache2conf(cls, node, filename):
def generateapache2conf(cls, node: CoreNode, filename: str) -> str:
lockstr = {
cls.APACHEVER22: "LockFile ${APACHE_LOCK_DIR}/accept.lock\n",
cls.APACHEVER24: "Mutex file:${APACHE_LOCK_DIR} default\n",
@ -421,22 +404,18 @@ class HttpService(UtilService):
cls.APACHEVER22: "",
cls.APACHEVER24: "LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n",
}
permstr = {
cls.APACHEVER22: " Order allow,deny\n Deny from all\n Satisfy all\n",
cls.APACHEVER24: " Require all denied\n",
}
authstr = {
cls.APACHEVER22: "LoadModule authz_default_module /usr/lib/apache2/modules/mod_authz_default.so\n",
cls.APACHEVER24: "LoadModule authz_core_module /usr/lib/apache2/modules/mod_authz_core.so\n",
}
permstr2 = {
cls.APACHEVER22: "\t\tOrder allow,deny\n\t\tallow from all\n",
cls.APACHEVER24: "\t\tRequire all granted\n",
}
version = cls.detectversionfromcmd()
cfg = "# apache2.conf generated by utility.py:HttpService\n"
cfg += lockstr[version]
@ -552,7 +531,7 @@ TraceEnable Off
return cfg
@classmethod
def generateenvvars(cls, node, filename):
def generateenvvars(cls, node: CoreNode, filename: str) -> str:
return """\
# this file is used by apache2ctl - generated by utility.py:HttpService
# these settings come from a default Ubuntu apache2 installation
@ -567,7 +546,7 @@ export LANG
"""
@classmethod
def generatehtml(cls, node, filename):
def generatehtml(cls, node: CoreNode, filename: str) -> str:
body = (
"""\
<!-- generated by utility.py:HttpService -->
@ -587,16 +566,15 @@ class PcapService(UtilService):
Pcap service for logging packets.
"""
name = "pcap"
configs = ("pcap.sh",)
dirs = ()
startup = ("sh pcap.sh start",)
shutdown = ("sh pcap.sh stop",)
validate = ("pidof tcpdump",)
meta = "logs network traffic to pcap packet capture files"
name: str = "pcap"
configs: Tuple[str, ...] = ("pcap.sh",)
startup: Tuple[str, ...] = ("sh pcap.sh start",)
shutdown: Tuple[str, ...] = ("sh pcap.sh stop",)
validate: Tuple[str, ...] = ("pidof tcpdump",)
meta: str = "logs network traffic to pcap packet capture files"
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a startpcap.sh traffic logging script.
"""
@ -630,15 +608,17 @@ fi;
class RadvdService(UtilService):
name = "radvd"
configs = ("/etc/radvd/radvd.conf",)
dirs = ("/etc/radvd",)
startup = ("radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",)
shutdown = ("pkill radvd",)
validate = ("pidof radvd",)
name: str = "radvd"
configs: Tuple[str, ...] = ("/etc/radvd/radvd.conf",)
dirs: Tuple[str, ...] = ("/etc/radvd",)
startup: Tuple[str, ...] = (
"radvd -C /etc/radvd/radvd.conf -m logfile -l /var/log/radvd.log",
)
shutdown: Tuple[str, ...] = ("pkill radvd",)
validate: Tuple[str, ...] = ("pidof radvd",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
"""
Generate a RADVD router advertisement daemon config file
using the network address of each interface.
@ -678,7 +658,7 @@ interface %s
return cfg
@staticmethod
def subnetentry(x):
def subnetentry(x: str) -> str:
"""
Generate a subnet declaration block given an IPv6 prefix string
for inclusion in the RADVD config file.
@ -695,14 +675,14 @@ class AtdService(UtilService):
Atd service for scheduling at jobs
"""
name = "atd"
configs = ("startatd.sh",)
dirs = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
startup = ("sh startatd.sh",)
shutdown = ("pkill atd",)
name: str = "atd"
configs: Tuple[str, ...] = ("startatd.sh",)
dirs: Tuple[str, ...] = ("/var/spool/cron/atjobs", "/var/spool/cron/atspool")
startup: Tuple[str, ...] = ("sh startatd.sh",)
shutdown: Tuple[str, ...] = ("pkill atd",)
@classmethod
def generate_config(cls, node, filename):
def generate_config(cls, node: CoreNode, filename: str) -> str:
return """
#!/bin/sh
echo 00001 > /var/spool/cron/atjobs/.SEQ
@ -717,5 +697,5 @@ class UserDefinedService(UtilService):
Dummy service allowing customization of anything.
"""
name = "UserDefined"
meta = "Customize this service to do anything upon startup."
name: str = "UserDefined"
meta: str = "Customize this service to do anything upon startup."