def watch_prefix(self, key_prefix, **kwargs): """ Watch a range of keys with a prefix. :param key_prefix: prefix to watch :returns: tuple of ``events_iterator`` and ``cancel``. """ kwargs['range_end'] = \ utils.increment_last_byte(utils.to_bytes(key_prefix)) return self.watch(key_prefix, **kwargs)
def build_message(self): compare = etcdrpc.Compare() compare.key = utils.to_bytes(self.key) if self.op is None: raise ValueError('op must be one of =, < or >') compare.result = self.op self.build_compare(compare) return compare
def _create_watch_request(self, key, range_end=None, start_revision=None, progress_notify=False, filters=None, prev_kv=False): create_watch = etcdrpc.WatchCreateRequest() create_watch.key = utils.to_bytes(key) if range_end is not None: create_watch.range_end = utils.to_bytes(range_end) if start_revision is not None: create_watch.start_revision = start_revision if progress_notify: create_watch.progress_notify = progress_notify if filters is not None: create_watch.filters = filters if prev_kv: create_watch.prev_kv = prev_kv return etcdrpc.WatchRequest(create_request=create_watch)
def test_lease_expire(self, etcd): key = '/doot/lease_test_expire' lease = etcd.lease(1) etcd.put(key, 'this is a lease', lease=lease) assert lease.keys == [utils.to_bytes(key)] assert etcd.get(key) == b'this is a lease' assert lease.remaining_ttl <= lease.granted_ttl # wait for the lease to expire time.sleep(lease.granted_ttl + 2) with pytest.raises(etcd3.exceptions.KeyNotFoundError): etcd.get(key)
def delete_prefix(self, prefix): """Delete a range of keys with a prefix in etcd.""" delete_request = self._build_delete_request( prefix, range_end=utils.increment_last_byte(utils.to_bytes(prefix)) ) return self.kvstub.DeleteRange( delete_request, self.timeout, credentials=self.call_credentials, metadata=self.metadata )
def test_watch_prefix(self, etcd): def update_etcd(v): etcdctl('put', '/doot/watch/prefix/' + v, v) out = etcdctl('get', '/doot/watch/prefix/' + v) assert base64.b64decode(out['kvs'][0]['value']) == \ utils.to_bytes(v) def update_key(): # sleep to make watch can get the event time.sleep(3) update_etcd('0') time.sleep(1) update_etcd('1') time.sleep(1) update_etcd('2') time.sleep(1) update_etcd('3') time.sleep(1) t = threading.Thread(name="update_key_prefix", target=update_key) t.start() change_count = 0 events_iterator, cancel = etcd.watch_prefix('/doot/watch/prefix/') for event in events_iterator: assert event.key == \ utils.to_bytes('/doot/watch/prefix/{}'.format(change_count)) assert event.value == \ utils.to_bytes(str(change_count)) # if cancel worked, we should not receive event 3 assert event.value != utils.to_bytes('3') change_count += 1 if change_count > 2: # if cancel not work, we will block in this for-loop forever cancel() t.join()
def test_lease_expire(self, etcd): key = '/doot/lease_test_expire' lease = etcd.lease(1) etcd.put(key, 'this is a lease', lease=lease) assert lease.keys == [utils.to_bytes(key)] v, _ = etcd.get(key) assert v == b'this is a lease' assert lease.remaining_ttl <= lease.granted_ttl # wait for the lease to expire time.sleep(lease.granted_ttl + 2) v, _ = etcd.get(key) assert v is None
def add_callback(self, key, callback, range_end=None, start_revision=None, progress_notify=False, filters=None, prev_kv=False): with self._watch_id_lock: create_watch = etcdrpc.WatchCreateRequest() create_watch.key = utils.to_bytes(key) if range_end is not None: create_watch.range_end = utils.to_bytes(range_end) if start_revision is not None: create_watch.start_revision = start_revision if progress_notify: create_watch.progress_notify = progress_notify if filters is not None: create_watch.filters = filters if prev_kv: create_watch.prev_kv = prev_kv request = etcdrpc.WatchRequest(create_request=create_watch) self._watch_requests_queue.put((request, callback)) return self._watch_id_queue.get(timeout=self.timeout)
def get_prefix_response(self, key_prefix, **kwargs): """Get a range of keys with a prefix.""" if any(kwarg in kwargs for kwarg in ("key", "range_end")): raise TypeError("Don't use key or range_end with prefix") range_request = self._build_get_range_request( key=key_prefix, range_end=utils.prefix_range_end(utils.to_bytes(key_prefix)), **kwargs) return self.kvstub.Range(range_request, self.timeout, credentials=self.call_credentials, metadata=self.metadata)
def add_watch_prefix_callback(self, key_prefix, callback, **kwargs): """ Watch a prefix and call a callback on every response. If timeout was declared during the client initialization and the watch cannot be created during that time the method raises a ``WatchTimedOut`` exception. :param key_prefix: prefix to watch :param callback: callback function :returns: watch_id. Later it could be used for cancelling watch. """ kwargs['range_end'] = \ utils.increment_last_byte(utils.to_bytes(key_prefix)) return self.add_watch_callback(key_prefix, callback, **kwargs)
def get_prefix_response(self, key_prefix, sort_order=None, sort_target='key', keys_only=False): """Get a range of keys with a prefix.""" range_request = self._build_get_range_request( key=key_prefix, range_end=utils.increment_last_byte(utils.to_bytes(key_prefix)), sort_order=sort_order, sort_target=sort_target, keys_only=keys_only, ) return self.kvstub.Range( range_request, self.timeout, credentials=self.call_credentials, metadata=self.metadata )
def rolerevokepermission(self, role, path, prefix): rolerevokepermission_request = etcdrpc.AuthRoleRevokePermissionRequest( role=role, key=path) if prefix: rolerevokepermission_request.range_end = utils.increment_last_byte( utils.to_bytes(path)) # else: # rolerevokepermission_request.range_end = utils.to_bytes(path) print(rolerevokepermission_request) rolerevokepermission_responce = self.authstub.RoleRevokePermission( rolerevokepermission_request, self.timeout, credentials=self.call_credentials, metadata=self.metadata) return rolerevokepermission_responce
def watch_range_queue(queue: Queue, db: Etcd3Client, prefix): kwargs = {} kwargs['range_end'] = \ utils.increment_last_byte(utils.to_bytes(prefix)) def cb(event): ident = event.key.decode()[len(prefix):] if isinstance(event, DeleteEvent): queue.put( RangeEvent(prefix, ident, Ev.Delete, event.value, event.version)) elif isinstance(event, PutEvent): queue.put( RangeEvent(prefix, ident, Ev.Put, event.value, event.version)) else: logger.error(f'UnknownEvent: {event}') return db.add_watch_callback(key=prefix, callback=cb, **kwargs)
def get_prefix(self, key_prefix, sort_order=None, sort_target='key'): """ Get a range of keys with a prefix. :param key_prefix: first key in range :returns: sequence of (key, value) tuples """ range_request = self._build_get_range_request( key=key_prefix, range_end=utils.increment_last_byte(utils.to_bytes(key_prefix)), sort_order=sort_order, ) range_response = self.kvstub.Range(range_request) if range_response.count < 1: raise exceptions.KeyNotFoundError('no keys found') else: for kv in range_response.kvs: yield (kv.key, kv.value)
def get_prefix(self, key_prefix, sort_order=None, sort_target='key'): """ Get a range of keys with a prefix. :param key_prefix: first key in range :returns: sequence of (value, metadata) tuples """ range_request = self._build_get_range_request( key=key_prefix, range_end=utils.increment_last_byte(utils.to_bytes(key_prefix)), sort_order=sort_order, ) range_response = self.kvstub.Range(range_request, self.timeout) if range_response.count < 1: return else: for kv in range_response.kvs: yield (kv.value, KVMetadata(kv))
def build_compare(self, compare): compare.target = etcdrpc.Compare.VALUE compare.value = utils.to_bytes(self.value)
def delete_prefix(self, prefix): """Delete a range of keys with a prefix in etcd.""" delete_request = self._build_delete_request( prefix, range_end=utils.increment_last_byte(utils.to_bytes(prefix))) return self.kvstub.DeleteRange(delete_request)
def update_etcd(v): etcdctl('put', '/doot/watch/prefix/' + v, v) out = etcdctl('get', '/doot/watch/prefix/' + v) assert base64.b64decode(out['kvs'][0]['value']) == \ utils.to_bytes(v)
def update_etcd(v): etcdctl('put', '/watchcompation', v) out = etcdctl('get', '/watchcompation') assert base64.b64decode(out['kvs'][0]['value']) == \ utils.to_bytes(v)
def watch_prefix(self, key_prefix, **kwargs): """The same as ``watch``, but watches a range of keys with a prefix.""" kwargs['range_end'] = \ utils.increment_last_byte(utils.to_bytes(key_prefix)) return self.watch(key_prefix, **kwargs)
def _build_put_request(self, key, value, lease=None): put_request = etcdrpc.PutRequest() put_request.key = utils.to_bytes(key) put_request.value = utils.to_bytes(value) put_request.lease = utils.lease_to_id(lease) return put_request