def get_prefix(self, key_prefix, sort_order=None, sort_target=None): """Get a range of keys with a prefix. :param sort_order: 'ascend' or 'descend' or None :param key_prefix: first key in range :returns: sequence of (value, metadata) tuples """ return self.get(key_prefix, metadata=True, range_end=_encode(_increment_last_byte(key_prefix)), sort_order=sort_order)
def watch_prefix_once(self, key_prefix, timeout=None, **kwargs): """Watches a range of keys with a prefix, similar to watch_once""" kwargs['range_end'] = \ _increment_last_byte(key_prefix) return self.watch_once(key_prefix, timeout=timeout, **kwargs)
def watch_prefix(self, key_prefix, **kwargs): """The same as ``watch``, but watches a range of keys with a prefix.""" kwargs['range_end'] = \ _increment_last_byte(key_prefix) return self.watch(key_prefix, **kwargs)
def delete_prefix(self, key_prefix): """Delete a range of keys with a prefix in etcd.""" return self.delete( key_prefix, range_end=_encode(_increment_last_byte(key_prefix)))
def get_prefix(prefix, revision=None): """Read all etcdv3 data whose key begins with a given prefix. - prefix (string): The prefix. - revision: The revision to do the get at. If not specified then the current revision is used. Returns a list of tuples (key, value, mod_revision), one for each key-value pair, in which: - key is the etcd key (a string) - value is the etcd value (also a string; note *not* JSON-decoded) - mod_revision is the revision at which that key was last modified (an integer represented as a string). Note: this entrypoint is only used for data outside the Calico v3 data model; specifically for legacy Calico v1 status notifications. This entrypoint should be removed once those status notifications have been reimplemented within the Calico v3 data model. """ client = _get_client() if revision is None: _, revision = get_status() LOG.debug("Doing get at current revision: %r", revision) # The JSON gateway can only return a certain number of bytes in a single # response so we chunk up the read into blocks. # # Since etcd's get protocol has an inclusive range_start and an exclusive # range_end, we load the keys in reverse order. That way, we can use the # final key in each chunk as the next range_end. range_end = _encode(_increment_last_byte(prefix)) results = [] while True: # Note: originally, we included the sort_target parameter here but # etcdgw has a bug (https://github.com/dims/etcd3-gateway/issues/18), # which prevents that from working. In any case, sort-by-key is the # default, which is what we want. chunk = client.get(prefix, metadata=True, range_end=range_end, sort_order='descend', limit=CHUNK_SIZE_LIMIT, revision=str(revision)) results.extend(chunk) if len(chunk) < CHUNK_SIZE_LIMIT: # Partial (or empty) chunk signals that we're done. break _, data = chunk[-1] range_end = _encode(data["key"]) LOG.debug("etcdv3 get_prefix %s results=%s", prefix, len(results)) tuples = [] for result in results: value, item = result t = (item['key'].decode(), value.decode(), item['mod_revision']) tuples.append(t) return tuples