168 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
			
		
		
	
	
			168 lines
		
	
	
	
		
			5.2 KiB
		
	
	
	
		
			Python
		
	
	
		
			Executable file
		
	
	
	
	
| #!/usr/bin/env python
 | |
| """
 | |
| core-daemon: the CORE daemon is a server process that receives CORE API
 | |
| messages and instantiates emulated nodes and networks within the kernel. Various
 | |
| message handlers are defined and some support for sending messages.
 | |
| """
 | |
| 
 | |
| import argparse
 | |
| import logging
 | |
| import os
 | |
| import sys
 | |
| import threading
 | |
| import time
 | |
| from configparser import ConfigParser
 | |
| 
 | |
| from core import constants
 | |
| from core.api.grpc.server import CoreGrpcServer
 | |
| from core.api.tlv.corehandlers import CoreHandler, CoreUdpHandler
 | |
| from core.api.tlv.coreserver import CoreServer, CoreUdpServer
 | |
| from core.constants import CORE_CONF_DIR, COREDPY_VERSION
 | |
| from core.emulator.enumerations import CORE_API_PORT
 | |
| from core.utils import close_onexec, load_logging_config
 | |
| 
 | |
| 
 | |
| def banner():
 | |
|     """
 | |
|     Output the program banner printed to the terminal or log file.
 | |
| 
 | |
|     :return: nothing
 | |
|     """
 | |
|     logging.info("CORE daemon v.%s started %s", constants.COREDPY_VERSION, time.ctime())
 | |
| 
 | |
| 
 | |
| def start_udp(mainserver, server_address):
 | |
|     """
 | |
|     Start a thread running a UDP server on the same host,port for
 | |
|         connectionless requests.
 | |
| 
 | |
|     :param CoreServer mainserver: main core tcp server to piggy back off of
 | |
|     :param server_address:
 | |
|     :return: CoreUdpServer
 | |
|     """
 | |
|     mainserver.udpserver = CoreUdpServer(server_address, CoreUdpHandler, mainserver)
 | |
|     mainserver.udpthread = threading.Thread(target=mainserver.udpserver.start)
 | |
|     mainserver.udpthread.daemon = True
 | |
|     mainserver.udpthread.start()
 | |
| 
 | |
| 
 | |
| def cored(cfg):
 | |
|     """
 | |
|     Start the CoreServer object and enter the server loop.
 | |
| 
 | |
|     :param dict cfg: core configuration
 | |
|     :return: nothing
 | |
|     """
 | |
|     host = cfg["listenaddr"]
 | |
|     port = int(cfg["port"])
 | |
|     if host == "" or host is None:
 | |
|         host = "localhost"
 | |
| 
 | |
|     try:
 | |
|         address = (host, port)
 | |
|         server = CoreServer(address, CoreHandler, cfg)
 | |
|     except:
 | |
|         logging.exception("error starting main server on:  %s:%s", host, port)
 | |
|         sys.exit(1)
 | |
| 
 | |
|     # initialize grpc api
 | |
|     grpc_server = CoreGrpcServer(server.coreemu)
 | |
|     address_config = cfg["grpcaddress"]
 | |
|     port_config = cfg["grpcport"]
 | |
|     grpc_address = f"{address_config}:{port_config}"
 | |
|     grpc_thread = threading.Thread(target=grpc_server.listen, args=(grpc_address,))
 | |
|     grpc_thread.daemon = True
 | |
|     grpc_thread.start()
 | |
| 
 | |
|     # start udp server
 | |
|     start_udp(server, address)
 | |
| 
 | |
|     # close handlers
 | |
|     close_onexec(server.fileno())
 | |
| 
 | |
|     logging.info("CORE TLV API TCP/UDP listening on: %s:%s", host, port)
 | |
|     server.serve_forever()
 | |
| 
 | |
| 
 | |
| def get_merged_config(filename):
 | |
|     """
 | |
|     Return a configuration after merging config file and command-line arguments.
 | |
| 
 | |
|     :param str filename: file name to merge configuration settings with
 | |
|     :return: merged configuration
 | |
|     :rtype: dict
 | |
|     """
 | |
|     # these are the defaults used in the config file
 | |
|     default_log = os.path.join(constants.CORE_CONF_DIR, "logging.conf")
 | |
|     default_grpc_port = "50051"
 | |
|     default_threads = "1"
 | |
|     default_address = "localhost"
 | |
|     defaults = {
 | |
|         "port": str(CORE_API_PORT),
 | |
|         "listenaddr": default_address,
 | |
|         "numthreads": default_threads,
 | |
|         "grpcport": default_grpc_port,
 | |
|         "grpcaddress": default_address,
 | |
|         "logfile": default_log
 | |
|     }
 | |
| 
 | |
|     parser = argparse.ArgumentParser(
 | |
|         description=f"CORE daemon v.{COREDPY_VERSION} instantiates Linux network namespace nodes.")
 | |
|     parser.add_argument("-f", "--configfile", dest="configfile",
 | |
|                         help=f"read config from specified file; default = {filename}")
 | |
|     parser.add_argument("-p", "--port", dest="port", type=int,
 | |
|                         help=f"port number to listen on; default = {CORE_API_PORT}")
 | |
|     parser.add_argument("-n", "--numthreads", dest="numthreads", type=int,
 | |
|                         help=f"number of server threads; default = {default_threads}")
 | |
|     parser.add_argument("--ovs", action="store_true", help="enable experimental ovs mode, default is false")
 | |
|     parser.add_argument("--grpc-port", dest="grpcport",
 | |
|                         help=f"grpc port to listen on; default {default_grpc_port}")
 | |
|     parser.add_argument("--grpc-address", dest="grpcaddress",
 | |
|                         help=f"grpc address to listen on; default {default_address}")
 | |
|     parser.add_argument("-l", "--logfile", help=f"core logging configuration; default {default_log}")
 | |
| 
 | |
|     # parse command line options
 | |
|     args = parser.parse_args()
 | |
| 
 | |
|     # read the config file
 | |
|     if args.configfile is not None:
 | |
|         filename = args.configfile
 | |
|     del args.configfile
 | |
|     cfg = ConfigParser(defaults)
 | |
|     cfg.read(filename)
 | |
| 
 | |
|     section = "core-daemon"
 | |
|     if not cfg.has_section(section):
 | |
|         cfg.add_section(section)
 | |
| 
 | |
|     # merge argparse with configparser
 | |
|     for opt in vars(args):
 | |
|         val = getattr(args, opt)
 | |
|         if val is not None:
 | |
|             cfg.set(section, opt, str(val))
 | |
| 
 | |
|     return dict(cfg.items(section))
 | |
| 
 | |
| 
 | |
| def main():
 | |
|     """
 | |
|     Main program startup.
 | |
| 
 | |
|     :return: nothing
 | |
|     """
 | |
|     # get a configuration merged from config file and command-line arguments
 | |
|     cfg = get_merged_config(f"{CORE_CONF_DIR}/core.conf")
 | |
| 
 | |
|     # load logging configuration
 | |
|     load_logging_config(cfg["logfile"])
 | |
| 
 | |
|     banner()
 | |
| 
 | |
|     try:
 | |
|         cored(cfg)
 | |
|     except KeyboardInterrupt:
 | |
|         logging.info("keyboard interrupt, stopping core daemon")
 | |
| 
 | |
| 
 | |
| if __name__ == "__main__":
 | |
|     main()
 |