def test_key_not_present(self): p = TestPlugin() e = EtcdSynchronizer(p, "10.0.0.1", "local", None, "clearwater") thread = Thread(target=e.main_wrapper) thread.daemon = True thread.start() sleep(1) p._on_config_changed.assert_called_with("default_value", None) # Allow the EtcdSynchronizer to exit e._terminate_flag = True sleep(1)
def test_synchronisation(self): p = TestPlugin() e = EtcdSynchronizer(p, "10.0.0.1", "local", None, "clearwater") # Write some initial data into the key e._client.write("/clearwater/local/configuration/test", "initial data") thread = Thread(target=e.main_wrapper) thread.daemon = True thread.start() sleep(1) # Write a new value into etcd, and check that the plugin is called with # it e._client.write("/clearwater/local/configuration/test", "hello world") sleep(1) p._on_config_changed.assert_called_with("hello world", None) # Allow the EtcdSynchronizer to exit e._terminate_flag = True sleep(1)
def main(args): syslog.openlog("config-manager", syslog.LOG_PID) pdlogs.STARTUP.log() try: arguments = docopt(__doc__, argv=args) except DocoptExit: pdlogs.EXITING_BAD_CONFIG.log() raise local_ip = arguments['--local-ip'] local_site = arguments['--local-site'] etcd_key = arguments['--etcd-key'] log_dir = arguments['--log-directory'] log_level = LOG_LEVELS.get(arguments['--log-level'], logging.DEBUG) stdout_err_log = os.path.join(log_dir, "config-manager.output.log") if not arguments['--foreground']: utils.daemonize(stdout_err_log) # Process names are limited to 15 characters, so abbreviate prctl.prctl(prctl.NAME, "cw-config-mgr") logging_config.configure_logging(log_level, log_dir, "config-manager", show_thread=True) # urllib3 logs a WARNING log whenever it recreates a connection, but our # etcd usage does this frequently (to allow watch timeouts), so deliberately # ignore this log urllib_logger = logging.getLogger('urllib3') urllib_logger.setLevel(logging.ERROR) utils.install_sigusr1_handler("config-manager") # Drop a pidfile. We must keep a reference to the file object here, as this keeps # the file locked and provides extra protection against two processes running at # once. pidfile_lock = None try: pidfile_lock = utils.lock_and_write_pid_file( arguments['--pidfile']) # noqa except IOError: # We failed to take the lock - another process is already running exit(1) plugins_dir = "/usr/share/clearwater/clearwater-config-manager/plugins/" plugins = load_plugins_in_dir(plugins_dir) plugins.sort(key=lambda x: x.key()) synchronizers = [] threads = [] files = [p.file() for p in plugins] alarm = ConfigAlarm(files) # Load the plugins, but don't start them until we've installed the SIGTERM # handler, as that handler will gracefully shut down any running # synchronizers on receiving a SIGTERM for plugin in plugins: syncer = EtcdSynchronizer(plugin, local_ip, local_site, alarm, etcd_key) synchronizers.append(syncer) threads.append(syncer.thread) _log.info("Loaded plugin %s" % plugin) utils.install_sigterm_handler(synchronizers) # Now start the plugin threads for syncer in synchronizers: syncer.start_thread() _log.info("Started thread for plugin %s" % syncer._plugin) while any([thr.isAlive() for thr in threads]): for thr in threads: if thr.isAlive(): thr.join(1) while not utils.should_quit: sleep(1) _log.info("Clearwater Configuration Manager shutting down") pdlogs.EXITING.log() syslog.closelog()