|
|
|
"""
|
|
|
|
The Management - this module takes care of loading and running subordinate
|
|
|
|
bureaus in the office organization. Bureaus are enabled in the file
|
|
|
|
"~/.screenless/mgmt.ini":
|
|
|
|
[mgmt]
|
|
|
|
bureaus = ihr typing myburo and so on
|
|
|
|
"""
|
|
|
|
import configparser
|
|
|
|
import importlib
|
|
|
|
import multiprocessing
|
|
|
|
import os
|
|
|
|
import signal
|
|
|
|
import time
|
|
|
|
|
|
|
|
|
|
|
|
class Management:
|
|
|
|
"""
|
|
|
|
Management is the executive of the Screenless Office. It can start, stop
|
|
|
|
and reconfigure the subordinate bureaus of the office.
|
|
|
|
"""
|
|
|
|
def __init__(self):
|
|
|
|
basepath = os.path.expanduser("~/.screenless")
|
|
|
|
if not os.path.exists(basepath):
|
|
|
|
os.mkdir(basepath)
|
|
|
|
os.chdir(basepath)
|
|
|
|
|
|
|
|
self.procs = {}
|
|
|
|
self.org_chart = []
|
|
|
|
self._load_config()
|
|
|
|
|
|
|
|
def _load_config(self):
|
|
|
|
config = configparser.ConfigParser()
|
|
|
|
try:
|
|
|
|
config.read("mgmt.ini")
|
|
|
|
self.org_chart = config["mgmt"]["bureaus"].split()
|
|
|
|
except KeyError:
|
|
|
|
config["mgmt"] = {"bureaus":
|
|
|
|
"ihr typing publicrelations photography jokes"}
|
|
|
|
with open("mgmt.ini", "w") as configfile:
|
|
|
|
config.write(configfile)
|
|
|
|
print("Created new mgmt.ini config file. Please modify to suit.")
|
|
|
|
self.org_chart = config["mgmt"]["bureaus"].split()
|
|
|
|
|
|
|
|
def _start_bureaus(self):
|
|
|
|
"""
|
|
|
|
Initialized and start all child bureaus
|
|
|
|
"""
|
|
|
|
for buro in self.org_chart:
|
|
|
|
# TODO: this may need some sanity checking for crash/reload
|
|
|
|
lib = importlib.import_module("bureau." + buro)
|
|
|
|
proc = multiprocessing.Process(target=lib.main)
|
|
|
|
self.procs[buro] = proc
|
|
|
|
proc.start()
|
|
|
|
|
|
|
|
def _stop_bureaus(self):
|
|
|
|
"""
|
|
|
|
Terminates all running bureau children
|
|
|
|
"""
|
|
|
|
for buro in self.org_chart:
|
|
|
|
proc = self.procs[buro]
|
|
|
|
proc.terminate()
|
|
|
|
|
|
|
|
def reload(self, signum=None, frame=None):
|
|
|
|
"""
|
|
|
|
stop all bureaus, reload config, restart all bureaus.
|
|
|
|
Note, this may cause a loss of state in some cases.
|
|
|
|
"""
|
|
|
|
self._stop_bureaus()
|
|
|
|
self._load_config()
|
|
|
|
self._start_bureaus()
|
|
|
|
|
|
|
|
def run(self):
|
|
|
|
"""
|
|
|
|
main loop for Management, will restart crashed bureaus
|
|
|
|
and reload everything when sent a SIGHUP
|
|
|
|
"""
|
|
|
|
with open("mgmt.pid", "w") as pfile:
|
|
|
|
pfile.write(str(os.getpid()))
|
|
|
|
|
|
|
|
signal.signal(signal.SIGHUP, self.reload)
|
|
|
|
|
|
|
|
self._start_bureaus()
|
|
|
|
while True:
|
|
|
|
for buro in self.org_chart:
|
|
|
|
proc = self.procs[buro]
|
|
|
|
if not proc.is_alive():
|
|
|
|
print("bureau", buro, "has crashed! Call the consultants!")
|
|
|
|
print("restarting...")
|
|
|
|
#TODO this should probably only retry a few times
|
|
|
|
proc.start()
|
|
|
|
time.sleep(1)
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == "__main__":
|
|
|
|
mgmt = Management()
|
|
|
|
mgmt.run()
|