From 7cdc3c1400f9bb4588a872fa0584dd0442938a92 Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Thu, 12 Jul 2018 08:48:07 -0400 Subject: [PATCH] Implement clear config rollback Should something go awry during config load, rollback the clear and load. --- .../confluent/collective/manager.py | 28 +++++++++++------- .../confluent/config/configmanager.py | 29 +++++++++++++++++-- 2 files changed, 43 insertions(+), 14 deletions(-) diff --git a/confluent_server/confluent/collective/manager.py b/confluent_server/confluent/collective/manager.py index ae9d3364..b05c4df3 100644 --- a/confluent_server/confluent/collective/manager.py +++ b/confluent_server/confluent/collective/manager.py @@ -103,15 +103,21 @@ def connect_to_leader(cert=None, name=None, leader=None): dbjson += ndata cfm.cfgleader = None cfm.clear_configuration() - cfm._restore_keys(keydata, None, sync=False) - for c in colldata: - cfm._true_add_collective_member(c, colldata[c]['address'], - colldata[c]['fingerprint'], - sync=False) - for globvar in globaldata: - cfm.set_global(globvar, globaldata[globvar]) - cfm._txcount = dbi.get('txcount', 0) - cfm.ConfigManager(tenant=None)._load_from_json(dbjson) + try: + cfm._restore_keys(keydata, None, sync=False) + for c in colldata: + cfm._true_add_collective_member(c, colldata[c]['address'], + colldata[c]['fingerprint'], + sync=False) + for globvar in globaldata: + cfm.set_global(globvar, globaldata[globvar]) + cfm._txcount = dbi.get('txcount', 0) + cfm.ConfigManager(tenant=None)._load_from_json(dbjson, + sync=False) + cfm.commit_clear() + except Exception: + cfm.rollback_clear() + raise currentleader = leader #spawn this as a thread... follower = eventlet.spawn(follow_leader, remote) @@ -227,8 +233,8 @@ def handle_connection(connection, cert, request, local=False): f = open('/etc/confluent/cfg/myname', 'w') f.write(name) f.close() - cfm.clear_configuration() - eventlet.spawn_n(connect_to_leader, rsp['collective']['fingerprint'], name) + eventlet.spawn_n(connect_to_leader, rsp['collective'][ + 'fingerprint'], name) if 'enroll' == operation: #TODO(jjohnson2): error appropriately when asked to enroll, but the master is elsewhere mycert = util.get_certificate_from_file('/etc/confluent/srvcert.pem') diff --git a/confluent_server/confluent/config/configmanager.py b/confluent_server/confluent/config/configmanager.py index 7158e801..2d0b30e5 100644 --- a/confluent_server/confluent/config/configmanager.py +++ b/confluent_server/confluent/config/configmanager.py @@ -496,17 +496,39 @@ def stop_leading(): pass # may have already been deleted.. +_oldcfgstore = None +_oldtxcount = 0 + + +def rollback_clear(): + global _cfgstore + global _txcount + global _oldcfgstore + global _oldtxcount + _txcount = _oldtxcount + _cfgstore = _oldcfgstore + _oldtxcount = 0 + _oldcfgstore = None + + def clear_configuration(): global _cfgstore global _txcount _cfgstore = {} - todelete = _config_areas + ('globals', 'collective', 'transactioncount') _txcount = 0 + +def commit_clear(): + global _oldtxcount + global _oldcfgstore + _oldcfgstore = None + _oldtxcount = 0 + todelete = _config_areas + ('globals', 'collective', 'transactioncount') for cfg in todelete: try: os.remove(os.path.join(ConfigManager._cfgdir, cfg)) except OSError as oe: pass + self._bg_sync_to_file() cfgleader = None def follow_channel(channel): @@ -1680,7 +1702,7 @@ class ConfigManager(object): self._bg_sync_to_file() #TODO: wait for synchronization to suceed/fail??) - def _load_from_json(self, jsondata): + def _load_from_json(self, jsondata, sync=True): """Load fresh configuration data from jsondata :param jsondata: String of jsondata @@ -1751,7 +1773,8 @@ class ConfigManager(object): self._cfgstore['users'][user]['cryptpass'] = \ tmpconfig[confarea][user]['cryptpass'] _mark_dirtykey('users', user, self.tenant) - self._bg_sync_to_file() + if sync: + self._bg_sync_to_file() def _dump_to_json(self, redact=None): """Dump the configuration in json form to output