def _getCircuitState(self): # check if zookeeper circuit state node initialized if not self.zookeeper.exists('/circuit'): #print 'no circuit has been established in zookeeper' #print 'initialize empty circuit state in zookeeper' self.zookeeper.create('/circuit') # get circuit states authenticators = self.zookeeper.get_children('/circuit') for auth in authenticators: # transaction guarantees that # if /circuit/authenticator exists # then all three its children exist # return type is a tuple next_ip = self.zookeeper.get('/circuit/{0}/next_ip'.format(auth))[0] next_ips = self.zookeeper.get('/circuit/{0}/next_ips'.format(auth))[0] next_auth = self.zookeeper.get('/circuit/{0}/next_auth'.format(auth))[0] # set watchers watchers.DataWatch(self.zookeeper, '/circuit/{0}/next_ip'.format(auth), self._nextIpWatcher) watchers.DataWatch(self.zookeeper, '/circuit/{0}/next_ips'.format(auth), self._nextIpsWatcher) watchers.DataWatch(self.zookeeper, '/circuit/{0}/next_auth'.format(auth), self._nextAuthWatcher) self.circuitStates[auth] = dict([ ('next_ip', next_ip), ('next_ips', next_ips), ('next_auth', next_auth) ])
def test_data_watch(self): updates = collections.deque() ev = Event() def notify_me(data, stat): updates.append((data, stat)) ev.set() k_watchers.DataWatch(self.client, "/b", func=notify_me) with start_close(self.client) as c: self.assertTrue(ev.wait(WAIT_TIME)) ev.clear() c.ensure_path("/b") self.assertTrue(ev.wait(WAIT_TIME)) ev.clear() c.set("/b", b"1") self.assertTrue(ev.wait(WAIT_TIME)) ev.clear() c.set("/b", b"2") self.assertTrue(ev.wait(WAIT_TIME)) ev.clear() self.assertEqual(4, len(updates)) ev.clear() with start_close(self.client) as c: c.delete("/b") self.assertTrue(ev.wait(WAIT_TIME)) self.assertEqual(5, len(updates))
def __init__(self, zk, path, callback=None, watch_children=True): """Initialize the Watcher object and begin watching a path. The initialization of a Watcher object automatically registers a data watch in Zookeeper on the path specificed. Any and all callbacks supplied during this initialization are executed as soon as the data is returned by Zookeeper. Optionally, a subsequent child watch is created on the children of the supplied path and again these callbacks are executed any time Zookeeper tells us that the children have changed in any way. args: zk: A kazoo.client.KazooClient object path: The path in Zookeeper to watch callback: A function to call when the path data changes wach_children: Whether or not to watch the children """ # Set our local variables self._zk = zk self._path = path self._watch_children = watch_children # Get a lock handler self._run_lock = self._zk.handler.lock_object() # Create local caches of the 'data' and the 'children' data self._children = [] self._data = None self._stat = None # Keep track of our Watcher objects in Kazoo with local references self._current_data_watch = None self._current_children_watch = None # Array to hold any callback functions we're supposed to notify when # anything changes on this path self._callbacks = [] if callback: self._callbacks.append(callback) # Quick copy of the data last used when executing callbacks -- used # to prevent duplicate callback executions due to multiple watches. self._last_callback_executed_with = None # if self._state is False, then even on a data change, our callbacks # do not run. self._state = True # Start up our DataWatch. This can be started on any path regardless of # whether it exists or not. ChildrenWatch objects though must be # started on only existing-paths -- so we do not create that object # here, but instead do it from with the self._update() method. log.debug('[%s] Registering DataWatch (%s)' % (self._path, self._current_data_watch)) self._current_data_watch = watchers.DataWatch( client=self._zk, path=self._path, func=self._update)
def _circuitNodeWatcher(self, children): #print '/circuit children updates' #print 'children = ' + str(children) for auth in children: if auth not in self.circuitStates: # return type is a tuple next_ip = self.zookeeper.get('/circuit/{0}/next_ip'.format(auth))[0] next_ips = self.zookeeper.get('/circuit/{0}/next_ips'.format(auth))[0] next_auth = self.zookeeper.get('/circuit/{0}/next_auth'.format(auth))[0] # set watchers watchers.DataWatch(self.zookeeper, '/circuit/{0}/next_ip'.format(auth), self._nextIpWatcher) watchers.DataWatch(self.zookeeper, '/circuit/{0}/next_ips'.format(auth), self._nextIpsWatcher) watchers.DataWatch(self.zookeeper, '/circuit/{0}/next_auth'.format(auth), self._nextAuthWatcher) self.circuitStates[auth] = dict([ ('next_ip', next_ip), ('next_ips', next_ips), ('next_auth', next_auth) ]) # register at local service table register_service(auth, next_ip, next_auth) return
def flush(self, client, path=None): # This uses the linearity guarantee of zookeeper (and associated # libraries) to create a temporary node, wait until a watcher notifies # it's created, then yield back for more work, and then at the end of # that work delete the created node. This ensures that the operations # done in the yield of this context manager will be applied and all # watchers will have fired before this context manager exits. if not path: path = FLUSH_PATH_TPL % uuidutils.generate_uuid() created = threading.Event() deleted = threading.Event() def on_created(data, stat): if stat is not None: created.set() return False # cause this watcher to cease to exist def on_deleted(data, stat): if stat is None: deleted.set() return False # cause this watcher to cease to exist watchers.DataWatch(client, path, func=on_created) client.create(path, makepath=True) if not created.wait(test_utils.WAIT_TIMEOUT): raise RuntimeError("Could not receive creation of %s in" " the alloted timeout of %s seconds" % (path, test_utils.WAIT_TIMEOUT)) try: yield finally: watchers.DataWatch(client, path, func=on_deleted) client.delete(path, recursive=True) if not deleted.wait(test_utils.WAIT_TIMEOUT): raise RuntimeError("Could not receive deletion of %s in" " the alloted timeout of %s seconds" % (path, test_utils.WAIT_TIMEOUT))
def test_data_watch_not_triggered(self): ev = Event() updates = [] def notify_me(data, stat): if stat: updates.append((data, stat)) ev.set() k_watchers.DataWatch(self.client, "/b", func=notify_me) with start_close(self.client) as c: with c.transaction() as txn: txn.create("/b") txn.check("/c", version=0) self.assertEqual(0, len(updates)) self.assertFalse(txn.committed) with c.transaction() as txn: txn.create("/b") txn.check("/b", version=0) self.assertTrue(txn.committed) self.assertTrue(ev.wait(WAIT_TIME)) self.assertEqual(1, len(updates))