updates naming for built in config services, broke out current example script to examples dir, broke out config service manager to separate file

This commit is contained in:
Blake Harnden 2020-01-17 13:47:55 -08:00
parent 433327c0ae
commit dbc77d81f6
7 changed files with 180 additions and 91 deletions

View file

@ -9,7 +9,6 @@ from typing import Any, Dict, List
from mako import exceptions
from mako.lookup import TemplateLookup
from core import utils
from core.config import Configuration
from core.errors import CoreCommandError, CoreError
from core.nodes.base import CoreNode
@ -23,42 +22,6 @@ class ConfigServiceMode(enum.Enum):
TIMER = 2
class ConfigServiceManager:
def __init__(self):
self.services = {}
def add(self, service: "ConfigService") -> None:
name = service.name
logging.debug("loading service: class(%s) name(%s)", service.__class__, name)
# avoid duplicate services
if name in self.services:
raise CoreError(f"duplicate service being added: {name}")
# validate dependent executables are present
for executable in service.executables:
utils.which(executable, required=True)
# make service available
self.services[name] = service
def load(self, path: str) -> List[str]:
path = pathlib.Path(path)
subdirs = [x for x in path.iterdir() if x.is_dir()]
service_errors = []
for subdir in subdirs:
logging.info("loading config services from: %s", subdir)
services = utils.load_classes(str(subdir), ConfigService)
for service in services:
logging.info("found service: %s", service)
try:
self.add(service)
except CoreError as e:
service_errors.append(service.name)
logging.debug("not loading service(%s): %s", service.name, e)
return service_errors
class ConfigService(abc.ABC):
# validation period in seconds, how frequent validation is attempted
validation_period = 0.5

View file

@ -0,0 +1,48 @@
import logging
import pathlib
from typing import List
from core import utils
from core.configservice.base import ConfigService
from core.errors import CoreError
class ConfigServiceManager:
def __init__(self):
self.services = {}
def add(self, service: ConfigService) -> None:
name = service.name
logging.debug("loading service: class(%s) name(%s)", service.__class__, name)
# avoid duplicate services
if name in self.services:
raise CoreError(f"duplicate service being added: {name}")
# validate dependent executables are present
for executable in service.executables:
try:
utils.which(executable, required=True)
except ValueError:
raise CoreError(
f"service({service.name}) missing executable {executable}"
)
# make service available
self.services[name] = service
def load(self, path: str) -> List[str]:
path = pathlib.Path(path)
subdirs = [x for x in path.iterdir() if x.is_dir()]
service_errors = []
for subdir in subdirs:
logging.info("loading config services from: %s", subdir)
services = utils.load_classes(str(subdir), ConfigService)
for service in services:
logging.info("found service: %s", service)
try:
self.add(service)
except CoreError as e:
service_errors.append(service.name)
logging.debug("not loading service(%s): %s", service.name, e)
return service_errors

View file

@ -0,0 +1,19 @@
from core.configservice.base import ConfigService, ConfigServiceMode
GROUP_NAME = "Security"
class VpnClient(ConfigService):
name = "VPNClient"
group = GROUP_NAME
directories = []
executables = ["openvpn", "ip", "killall"]
dependencies = []
startup = ["sh vpnclient.sh"]
validate = ["pidof openvpn"]
shutdown = ["killall openvpn"]
validation_mode = ConfigServiceMode.BLOCKING
default_configs = []
def create_files(self):
self.render("vpnclient.sh")

View file

@ -0,0 +1,61 @@
# -------- CUSTOMIZATION REQUIRED --------
#
# The VPNClient service builds a VPN tunnel to the specified VPN server using
# OpenVPN software and a virtual TUN/TAP device.
# directory containing the certificate and key described below
keydir=/etc/core/keys
# the name used for a "$keyname.crt" certificate and "$keyname.key" private key.
keyname=client1
# the public IP address of the VPN server this client should connect with
vpnserver="10.0.2.10"
# optional next hop for adding a static route to reach the VPN server
nexthop="10.0.1.1"
# --------- END CUSTOMIZATION --------
# validate addresses
if [ "$(dpkg -l | grep " sipcalc ")" = "" ]; then
echo "WARNING: ip validation disabled because package sipcalc not installed
" > $PWD/vpnclient.log
else
if [ "$(sipcalc "$vpnserver" "$nexthop" | grep ERR)" != "" ]; then
echo "ERROR: invalide address $vpnserver or $nexthop " > $PWD/vpnclient.log
fi
fi
# validate key and certification files
if [ ! -e $keydir\/$keyname.key ] || [ ! -e $keydir\/$keyname.crt ] \
|| [ ! -e $keydir\/ca.crt ] || [ ! -e $keydir\/dh1024.pem ]; then
echo "ERROR: missing certification or key files under $keydir $keyname.key or $keyname.crt or ca.crt or dh1024.pem" >> $PWD/vpnclient.log
fi
# if necessary, add a static route for reaching the VPN server IP via the IF
vpnservernet=${vpnserver%.*}.0/24
if [ "$nexthop" != "" ]; then
ip route add $vpnservernet via $nexthop
fi
# create openvpn client.conf
(
cat << EOF
client
dev tun
proto udp
remote $vpnserver 1194
nobind
ca $keydir/ca.crt
cert $keydir/$keyname.crt
key $keydir/$keyname.key
dh $keydir/dh1024.pem
cipher AES-256-CBC
log $PWD/openvpn-client.log
verb 4
daemon
EOF
) > client.conf
openvpn --config client.conf

View file

@ -1,18 +1,9 @@
import logging
import os
import netaddr
from core import utils
from core.config import Configuration
from core.configservice.base import (
ConfigService,
ConfigServiceManager,
ConfigServiceMode,
)
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes, NodeOptions
from core.emulator.enumerations import ConfigDataTypes, EventTypes, NodeTypes
from core.configservice.base import ConfigService, ConfigServiceMode
from core.emulator.enumerations import ConfigDataTypes
GROUP_NAME = "Utility"
@ -21,7 +12,7 @@ class DefaultRoute(ConfigService):
name = "DefaultRoute"
group = GROUP_NAME
directories = []
executables = []
executables = ["ip"]
dependencies = []
startup = ["sh defaultroute.sh"]
validate = []
@ -65,45 +56,3 @@ class IpForwardService(ConfigService):
devnames.append(devname)
data = dict(devnames=devnames)
self.render("ipforward.sh", data)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
# setup basic network
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(model="nothing")
# options.services = []
coreemu = CoreEmu()
session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
switch = session.add_node(_type=NodeTypes.SWITCH)
# node one
node_one = session.add_node(options=options)
interface = prefixes.create_interface(node_one)
session.add_link(node_one.id, switch.id, interface_one=interface)
# node two
node_two = session.add_node(options=options)
interface = prefixes.create_interface(node_two)
session.add_link(node_two.id, switch.id, interface_one=interface)
session.instantiate()
# manager load config services
manager = ConfigServiceManager()
path = os.path.dirname(os.path.abspath(os.path.dirname(__file__)))
manager.load(path)
clazz = manager.services["DefaultRoute"]
dr_service = clazz(node_one)
dr_service.set_config({"value1": "custom"})
dr_service.start()
clazz = manager.services["IPForward"]
dr_service = clazz(node_one)
dr_service.start()
input("press enter to exit")
session.shutdown()

View file

@ -0,0 +1,49 @@
import logging
import os
from core import configservices
from core.configservice.manager import ConfigServiceManager
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes, NodeOptions
from core.emulator.enumerations import EventTypes, NodeTypes
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
# setup basic network
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
options = NodeOptions(model="nothing")
# options.services = []
coreemu = CoreEmu()
session = coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
switch = session.add_node(_type=NodeTypes.SWITCH)
# node one
node_one = session.add_node(options=options)
interface = prefixes.create_interface(node_one)
session.add_link(node_one.id, switch.id, interface_one=interface)
# node two
node_two = session.add_node(options=options)
interface = prefixes.create_interface(node_two)
session.add_link(node_two.id, switch.id, interface_one=interface)
session.instantiate()
# manager load config services
manager = ConfigServiceManager()
path = os.path.dirname(os.path.abspath(configservices.__file__))
manager.load(path)
clazz = manager.services["DefaultRoute"]
dr_service = clazz(node_one)
dr_service.set_config({"value1": "custom"})
dr_service.start()
clazz = manager.services["IPForward"]
dr_service = clazz(node_one)
dr_service.start()
input("press enter to exit")
session.shutdown()