You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
shepherd-agent/shepherd/core.py

138 lines
4.9 KiB

#!/usr/bin/env python3
# depends on:
# python 3.4 (included in Raspbian Jessie)
# APScheduler
import argparse
import os
from datetime import datetime
import toml
import shepherd.scheduler
import shepherd.config
import shepherd.plugin
import shepherd.control
# Future implementations of checking config differences should be done on
# the hash of the nested conf dict, so comments shouldn't affect this.
# save old config to somewhere in the shepherd root dir - probably need to
# implement a TOML writer in the config module.
# later on, there's going to be an issue with a new config being applied
# remotely, then the system restarting, and an old edit in /boot being
# applied over the top...
# Fix this by saving the working config to /boot when new config applied
# remotely.
def define_core_config(confdef):
confdef.add_def("id", shepherd.config.StringDef())
confdef.add_def("plugins", shepherd.config.StringArrayDef())
confdef.add_def("plugin_dir", shepherd.config.StringDef())
confdef.add_def("root_dir", shepherd.config.StringDef())
confdef.add_def("conf_edit_path", shepherd.config.StringDef())
def load_config(config_path,load_editconf):
# Load config from default location
confman = shepherd.config.ConfigManager()
confman.load(os.path.expanduser(config_path))
# Create core confdef and populate it
core_confdef = shepherd.config.ConfDefinition()
define_core_config(core_confdef)
# attempt to retrive core config and validate it
core_conf = confman.get_config("shepherd", core_confdef)
edit_confman = None
conf_edit_message = None
if load_editconf:
# Check for an edit_conf file, and try to load it and plugin configs
try:
edit_confman = shepherd.config.ConfigManager()
edit_confman.load(os.path.expanduser(core_conf["conf_edit_path"]))
core_edit_conf = edit_confman.get_config("shepherd", core_confdef)
plugin_classes = shepherd.plugin.find_plugins(
core_edit_conf["plugins"])
plugin_configs = edit_confman.get_plugin_configs(plugin_classes)
except FileNotFoundError:
conf_edit_message = None
except shepherd.config.InvalidConfigError as e:
conf_edit_message = "Invalid config.\n " + str(e.args)
except toml.TomlDecodeError as e:
conf_edit_message = "TOML syntax error.\n" + str(e)
except Exception:
conf_edit_message = "Error processing new config"
else:
conf_edit_message = ("Successfully applied this config at:" +
str(datetime.now()))
confman = edit_confman
core_conf = core_edit_conf
if conf_edit_message is not None:
shepherd.config.update_toml_message(
os.path.expanduser(core_conf["conf_edit_path"]), conf_edit_message)
# if editconf failed, load current config for plugins
if confman is not edit_confman:
plugin_classes = shepherd.plugin.find_plugins(core_conf["plugins"])
plugin_configs = confman.get_plugin_configs(plugin_classes)
# If no editconf file was found, write out the current config as a template
if (conf_edit_message is None) and load_editconf:
confman.dump_to_file(os.path.expanduser(core_conf["conf_edit_path"]),
"Config generated at:" + str(datetime.now()))
return (core_conf, plugin_classes, plugin_configs)
def main():
argparser = argparse.ArgumentParser(description="Keep track of a mob "
"of roaming Pis")
argparser.add_argument("configfile", nargs='?', metavar="configfile",
help="Path to configfile", default="shepherd.toml")
argparser.add_argument('-e', '--noedit',help="Disable the editable config temporarily", action="store_true", default=False)
argparser.add_argument("-t", "--test", help="Test and interface function of the from 'plugin:function'",
default=None)
args = argparser.parse_args()
confman = shepherd.config.ConfigManager()
confman.load(os.path.expanduser(args.configfile))
(core_conf, plugin_classes, plugin_configs) = load_config(args.configfile, not args.noedit)
if args.test is None:
shepherd.control.init_control(core_conf)
shepherd.scheduler.init_scheduler(core_conf)
shepherd.plugin.init_plugins(plugin_classes, plugin_configs, core_conf)
shepherd.scheduler.restore_jobs()
print(str(datetime.now()))
if args.test is not None:
(test_plugin, test_func) = args.test.split(':')
func = getattr(shepherd.plugin.plugin_functions[test_plugin], test_func)
print(func())
return
print('Press Ctrl+{0} to exit'.format('Break' if os.name == 'nt' else 'C'))
try:
shepherd.scheduler.start()
except (KeyboardInterrupt, SystemExit):
pass
if __name__ == "__main__":
main()