Ejemplo n.º 1
0
        async def watch_compacted_revision_test():
            events_iterator, cancel = await etcd.watch(b'/watchcompation',
                                                       start_revision=1)

            error_raised = False
            compacted_revision = 0
            try:
                await events_iterator.__anext__()
            except Exception as err:
                error_raised = True
                assert isinstance(
                    err, aiogrpc_etcd3.exceptions.RevisionCompactedError)
                compacted_revision = err.compacted_revision

            assert error_raised is True
            assert compacted_revision == 2

            change_count = 0
            events_iterator, cancel = await etcd.watch(
                b'/watchcompation', start_revision=compacted_revision)
            async for event in events_iterator:
                assert event.key == b'/watchcompation'
                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:
                    await cancel()
Ejemplo n.º 2
0
 async def add_callback(self,
                        key,
                        callback,
                        range_end=None,
                        start_revision=None,
                        progress_notify=False,
                        filters=None,
                        prev_kv=False):
     async 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_nowait((request, callback))
         return await asyncio.wait_for(self._watch_id_queue.get(),
                                       self.timeout)
Ejemplo n.º 3
0
    def _build_delete_request(self, key, range_end=None, prev_kv=None):
        delete_request = DeleteRangeRequest()
        delete_request.key = utils.to_bytes(key)

        if range_end is not None:
            delete_request.range_end = utils.to_bytes(range_end)

        if prev_kv is not None:
            delete_request.prev_kv = prev_kv

        return delete_request
Ejemplo n.º 4
0
    async 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 = await self.kvstub.Range(
            range_request,
            self.timeout,
            credentials=self.call_credentials,
        )

        if range_response.count < 1:
            return
        else:
            for kv in range_response.kvs:
                yield (kv.value, KVMetadata(kv))
Ejemplo n.º 5
0
    def _build_get_range_request(self,
                                 key,
                                 range_end=None,
                                 limit=None,
                                 revision=None,
                                 sort_order=None,
                                 sort_target='key',
                                 serializable=None,
                                 keys_only=False,
                                 count_only=False,
                                 min_mod_revision=None,
                                 max_mod_revision=None,
                                 min_create_revision=None,
                                 max_create_revision=None):
        range_request = RangeRequest()
        range_request.key = utils.to_bytes(key)
        if range_end is not None:
            range_request.range_end = utils.to_bytes(range_end)

        range_request.keys_only = keys_only
        range_request.count_only = count_only

        if sort_order is None:
            range_request.sort_order = RangeRequest.NONE
        elif sort_order == 'ascend':
            range_request.sort_order = RangeRequest.ASCEND
        elif sort_order == 'descend':
            range_request.sort_order = RangeRequest.DESCEND
        else:
            raise ValueError('unknown sort order: "{}"'.format(sort_order))

        if sort_target is None or sort_target == 'key':
            range_request.sort_target = RangeRequest.KEY
        elif sort_target == 'version':
            range_request.sort_target = RangeRequest.VERSION
        elif sort_target == 'create':
            range_request.sort_target = RangeRequest.CREATE
        elif sort_target == 'mod':
            range_request.sort_target = RangeRequest.MOD
        elif sort_target == 'value':
            range_request.sort_target = RangeRequest.VALUE
        else:
            raise ValueError('sort_target must be one of "key", '
                             '"version", "create", "mod" or "value"')

        return range_request
Ejemplo n.º 6
0
    async def watch_prefix_once(self, key_prefix, timeout=None, **kwargs):
        """
        Watches a range of keys with a prefix and stops after the first event.

        If the timeout was specified and event didn't arrived method
        will raise ``WatchTimedOut`` exception.
        """
        kwargs['range_end'] = \
            utils.increment_last_byte(utils.to_bytes(key_prefix))
        return await self.watch_once(key_prefix, timeout=timeout, **kwargs)
Ejemplo n.º 7
0
 async 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 await self.kvstub.DeleteRange(
         delete_request,
         self.timeout,
         credentials=self.call_credentials,
     )
Ejemplo n.º 8
0
    def build_message(self):
        compare = 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
Ejemplo n.º 9
0
    async def test_watch_prefix(self, etcd):
        def update_etcd(v):
            etcdctl(etcd, 'put', '/doot/watch/prefix/' + v, v)
            out = etcdctl(etcd, '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 = await etcd.watch_prefix('/doot/watch/prefix/'
                                                          )
        async 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
                await cancel()

        t.join()
Ejemplo n.º 10
0
    async def test_lease_expire(self, etcd):
        key = '/doot/lease_test_expire'
        lease = await etcd.lease(1)
        await etcd.put(key, 'this is a lease', lease=lease)
        assert await lease.keys == [utils.to_bytes(key)]
        v, _ = await etcd.get(key)
        assert v == b'this is a lease'
        assert await lease.remaining_ttl <= await lease.granted_ttl

        # wait for the lease to expire
        gttl = await lease.granted_ttl
        await asyncio.sleep(gttl + 2)
        v, _ = await etcd.get(key)
        assert v is None
Ejemplo n.º 11
0
    async def get_count(self, key_prefix=None):
        """
        Get count of all keys or keys with specified prefix.

        :param key_prefix: key_prefix for keys to count
        :type key_prefix: str or bytes
        :return: number of keys with specified prefix
        :rtype: int
        """
        if key_prefix is not None:
            key = key_prefix
            range_end = utils.increment_last_byte(utils.to_bytes(key_prefix))
        else:
            key = range_end = b'\0'

        range_request = self._build_get_range_request(key,
                                                      range_end,
                                                      count_only=True)
        range_response = await self.kvstub.Range(
            range_request, self.timeout, credentials=self.call_credentials)
        return range_response.count
Ejemplo n.º 12
0
    async def get_keys(self, key_prefix=None):
        """
        Get keys with specified prefix (all keys if no prefix specified).

        :param prefix: prefix for keys to count
        :type prefix: str or bytes
        :return: async generator of metadata objects
        """
        if key_prefix is not None:
            key = key_prefix
            range_end = utils.increment_last_byte(utils.to_bytes(key_prefix))
        else:
            key = range_end = b'\0'

        range_request = self._build_get_range_request(key,
                                                      range_end,
                                                      keys_only=True)
        range_response = await self.kvstub.Range(
            range_request, self.timeout, credentials=self.call_credentials)
        if range_response.count < 1:
            return
        else:
            for kv in range_response.kvs:
                yield KVMetadata(kv)
Ejemplo n.º 13
0
 async def watch_prefix(self, key_prefix, **kwargs):
     """Watches a range of keys with a prefix."""
     kwargs['range_end'] = \
         utils.increment_last_byte(utils.to_bytes(key_prefix))
     return await self.watch(key_prefix, **kwargs)
Ejemplo n.º 14
0
 def update_etcd(v):
     etcdctl(etcd, 'put', '/watchcompation', v)
     out = etcdctl(etcd, 'get', '/watchcompation')
     assert base64.b64decode(out['kvs'][0]['value']) == \
         utils.to_bytes(v)
Ejemplo n.º 15
0
 def _build_put_request(self, key, value, lease=None):
     put_request = 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
Ejemplo n.º 16
0
 def build_compare(self, compare):
     compare.target = Compare.VALUE
     compare.value = utils.to_bytes(self.value)
Ejemplo n.º 17
0
 def update_etcd(v):
     etcdctl(etcd, 'put', '/doot/watch/prefix/' + v, v)
     out = etcdctl(etcd, 'get', '/doot/watch/prefix/' + v)
     assert base64.b64decode(out['kvs'][0]['value']) == \
         utils.to_bytes(v)