示例#1
0
    def connect(self) -> None:
        self._client = None
        self._client_failed = False
        self.cont = True

        protocol = 'http'
        etcd_list = get_ticket().etcd
        if isinstance(etcd_list, dict):
            protocol = etcd_list['protocol']
            etcd_list = etcd_list['host']

        if len(etcd_list) == 1:
            host, port = etcd_list[0].split(':')
            self._client = etcd.Client(
                host=host,
                port=int(port),
                protocol=protocol,
                allow_reconnect=True,
                allow_redirect=True)
        else:
            def split_addr(e:str) -> Tuple[str, int]:
                host, port = e.split(':')
                return host, int(port)

            host_list = [split_addr(e)
                         for e in etcd_list]

            self._client = etcd.Client(
                host=tuple(host_list),
                protocol=protocol,
                allow_reconnect=True,
                allow_redirect=True)
示例#2
0
    def setUp(self):
        # Sets up the root user, toggles auth
        loop = asyncio.get_event_loop()
        self.client = etcd.Client(port=6001, loop=loop)

        u = auth.EtcdUser(self.client, 'root')
        u.password = '******'
        loop.run_until_complete(u.write())
        self.client = etcd.Client(port=6001, username='******',
                                password='******', loop=loop)
        self.unauth_client = etcd.Client(port=6001, loop=loop)
        a = auth.Auth(self.client)
        loop.run_until_complete(a.set_active(True))
示例#3
0
    def test_read(loop, self):
        u = auth.EtcdUser(self.client, 'root')
        # Reading an existing user succeeds
        try:
            yield from u.read()
        except Exception:
            self.fail("reading the root user raised an exception")

        # roles for said user are fetched
        self.assertEquals(u.roles, set(['root']))

        # The user is correctly rendered out
        self.assertEquals(u._to_net(), [{
            'user': '******',
            'password': None,
            'roles': ['root']
        }])

        # An inexistent user raises the appropriate exception
        u = auth.EtcdUser(self.client, 'user.does.not.exist')
        with raises(etcd.EtcdKeyNotFound):
            yield from u.read()

        # Reading with an unauthenticated client raises an exception
        u = auth.EtcdUser(self.unauth_client, 'root')
        with raises(etcd.EtcdInsufficientPermissions):
            yield from u.read()

        # Generic errors are caught
        c = etcd.Client(port=9999)
        u = auth.EtcdUser(c, 'root')
        with raises(etcd.EtcdException):
            yield from u.read()
示例#4
0
    def test_watch(loop, self):
        """ INTEGRATION: Receive a watch event from other process """

        client = aio_etcd.Client(port=6281, allow_reconnect=True, loop=loop)
        set_result = yield from client.set('/test-key', 'test-value')

        queue = asyncio.Queue(loop=loop)

        @asyncio.coroutine
        def change_value(key, newValue):
            c = aio_etcd.Client(port=6281, loop=loop)
            yield from c.set(key, newValue)

        @asyncio.coroutine
        def watch_value(key, queue):
            c = aio_etcd.Client(port=6281, loop=loop)
            w = yield from c.watch(key)
            yield from queue.put(w.value)

        watcher = asyncio.async(watch_value('/test-key', queue), loop=loop)
        yield from asyncio.sleep(0.1, loop=loop)
        changer = asyncio.async(change_value('/test-key', 'new-test-value'), loop=loop)

        value = yield from asyncio.wait_for(queue.get(),timeout=2,loop=loop)
        yield from asyncio.wait_for(watcher,timeout=5,loop=loop)
        yield from asyncio.wait_for(changer,timeout=5,loop=loop)

        assert value == 'new-test-value'
示例#5
0
    def test_get_set_delete(loop, self):
        """ INTEGRATION: set a new value """
        client = aio_etcd.Client(port=6281, loop=loop)
        try:
            get_result = yield from client.get('/test_set')
            assert False
        except aio_etcd.EtcdKeyNotFound as e:
            pass

        self.assertFalse((yield from client.contains('/test_set')))

        set_result = yield from client.set('/test_set', 'test-key')
        self.assertEquals('set', set_result.action.lower())
        self.assertEquals('/test_set', set_result.key)
        self.assertEquals('test-key', set_result.value)

        self.assertTrue((yield from client.contains('/test_set')))

        get_result = yield from client.get('/test_set')
        self.assertEquals('get', get_result.action.lower())
        self.assertEquals('/test_set', get_result.key)
        self.assertEquals('test-key', get_result.value)

        delete_result = yield from client.delete('/test_set')
        self.assertEquals('delete', delete_result.action.lower())
        self.assertEquals('/test_set', delete_result.key)

        self.assertFalse((yield from client.contains('/test_set')))

        try:
            get_result = yield from client.get('/test_set')
            assert False
        except aio_etcd.EtcdKeyNotFound as e:
            pass
示例#6
0
    def test_write_and_delete(loop,self):
        r = auth.EtcdRole(self.client, 'test_group')
        r.acls = {'/*': 'R', '/test/*': 'RW'}
        try:
            yield from r.write()
        except:
            self.fail("Writing a simple groups should not fail")

        # Create an user
        u = auth.EtcdUser(self.client, 'test_user')
        u.roles.add('guest')
        u.roles.add('root')
        # directly from my suitcase
        u.password = '******'
        try:
            yield from u.write()
        except:
            self.fail("creating a user doesn't work")
        # Password gets wiped
        self.assertEquals(u.password, None)
        yield from u.read()
        # Verify we can log in as this user and access the auth (it has the
        # root role)
        cl = etcd.Client(port=6001, username='******',
                         password='******')
        ul = auth.EtcdUser(cl, 'root')
        try:
            yield from ul.read()
        except etcd.EtcdInsufficientPermissions:
            self.fail("Reading auth with the new user is not possible")

        self.assertEquals(u.name, "test_user")
        self.assertEquals(u.roles, set(['guest', 'root']))
        # set roles as a list, it works!
        u.roles = ['guest', 'test_group']
        try:
            yield from u.write()
        except:
            self.fail("updating a user you previously created fails")
        yield from u.read()
        self.assertIn('test_group', u.roles)

        # Unauthorized access is properly handled
        ua = auth.EtcdUser(self.unauth_client, 'test_user')
        with raises(etcd.EtcdInsufficientPermissions):
            yield from ua.write()

        # now let's test deletion
        du = auth.EtcdUser(self.client, 'user.does.not.exist')
        with raises(etcd.EtcdKeyNotFound):
            yield from du.delete()

        # Delete test_user
        yield from u.delete()
        with raises(etcd.EtcdKeyNotFound):
            yield from u.read()
        # Permissions are properly handled
        with raises(etcd.EtcdInsufficientPermissions):
            yield from ua.delete()
示例#7
0
    def test_get_set_authenticated(loop, self):
        """ INTEGRATION: set/get a new value authenticated """

        client = aio_etcd.Client(
            port=6281, protocol='https', ca_cert=self.ca_cert_path, loop=loop)

        set_result = yield from client.set('/test_set', 'test-key')
        get_result = yield from client.get('/test_set')
示例#8
0
 def test_get_set_unauthenticated_missing_ca(loop, self):
     """ INTEGRATION: try unauthenticated w/out validation (https->https)"""
     # This doesn't work for now and will need further inspection
     client = aio_etcd.Client(protocol='https',
                              port=6001,
                              ssl_verify=ssl.CERT_NONE,
                              loop=loop)
     set_result = yield from client.set('/test_set', 'test-key')
     get_result = yield from client.get('/test_set')
示例#9
0
 def test_retrieve_subkeys(loop, self):
     """ INTEGRATION: retrieve multiple subkeys """
     client = aio_etcd.Client(port=6281, loop=loop)
     set_result = yield from client.write('/subtree/test_set', 'test-key1')
     set_result = yield from client.write('/subtree/test_set1', 'test-key2')
     set_result = yield from client.write('/subtree/test_set2', 'test-key3')
     get_result = yield from client.read('/subtree', recursive=True)
     result = [subkey.value for subkey in get_result.leaves]
     self.assertEquals(['test-key1', 'test-key2', 'test-key3'].sort(), result.sort())
示例#10
0
 def test_directory_ttl_update(loop, self):
     """ INTEGRATION: should be able to update a dir TTL """
     client = aio_etcd.Client(port=6281, loop=loop)
     yield from client.write('/dir', None, dir=True, ttl=30)
     res = yield from client.write('/dir', None, dir=True, ttl=31, prevExist=True)
     self.assertEquals(res.ttl, 31)
     res = yield from client.get('/dir')
     res.ttl = 120
     new_res = yield from client.update(res)
     self.assertEquals(new_res.ttl, 120)
示例#11
0
    def test_is_not_a_file(loop, self):
        """ INTEGRATION: try to write  value to an existing directory """
        client = aio_etcd.Client(port=6281, loop=loop)

        yield from client.set('/directory/test-key', 'test-value')
        try:
            yield from client.set('/directory', 'test-value')
            raise False
        except aio_etcd.EtcdNotFile:
            pass
示例#12
0
 def test_reconnect_not_allowed(loop, self):
     """ INTEGRATION: fail on server kill if not allow_reconnect """
     self.processHelper.stop()
     self.processHelper.run(number=3)
     client = aio_etcd.Client(port=6281, allow_reconnect=False, loop=loop)
     self.processHelper.kill_one(0)
     try:
         yield from client.get('/test_set')
         assert False
     except aio_etcd.EtcdConnectionFailed:
         pass
示例#13
0
 def watch_value(key, index, queue):
     c = aio_etcd.Client(port=6281, loop=loop)
     n = 0
     @asyncio.coroutine
     def qput(v):
         nonlocal n
         yield from queue.put(v.value)
         n += 1
         if n == 3:
             raise aio_etcd.StopWatching
     yield from c.eternal_watch(key, qput, index=index)
     assert n == 3, n
示例#14
0
 def test_update(loop, self):
     """INTEGRATION: update a value"""
     client = aio_etcd.Client(port=6281, loop=loop)
     yield from client.set('/foo', 3)
     c = yield from client.get('/foo')
     c.value = int(c.value) + 3
     yield from client.update(c)
     newres = yield from client.get('/foo')
     self.assertEquals(newres.value, u'6')
     try:
         yield from client.update(c)
         assert False
     except ValueError:
         pass
示例#15
0
    def connect(self):
        self.client = None
        self.client_failed = False
        self.cont = True

        etcd_list = get_ticket().etcd
        if len(etcd_list) == 1:
            host, port = etcd_list[0].split(':')
            self.client = etcd.Client(
                host=host,
                port=int(port),
                allow_reconnect=True,
                allow_redirect=True)
        else:
            def split_addr(e):
                host, port = e.split(':')
                return host, int(port)

            host = tuple(split_addr(e)
                         for e in etcd_list)
            self.client = etcd.Client(
                host=host,
                allow_reconnect=True,
                allow_redirect=True)
示例#16
0
    def test_reconnect(loop, self):
        """ INTEGRATION: get key after the server we're connected fails. """
        self.processHelper.stop()
        self.processHelper.run(number=3)
        yield from asyncio.sleep(0.2,loop=loop)
        client = aio_etcd.Client(port=6281, allow_reconnect=True, loop=loop)
        set_result = yield from client.set('/test_set', 'test-key1')
        get_result = yield from client.get('/test_set')

        self.assertEquals('test-key1', get_result.value)

        self.processHelper.kill_one(0)

        get_result = yield from client.get('/test_set')
        self.assertEquals('test-key1', get_result.value)
示例#17
0
    def test_creating_already_existing_directory(loop, self):
        """ INTEGRATION: creating an already existing directory without
        `prevExist=True` should fail """
        client = aio_etcd.Client(port=6281, loop=loop)
        yield from client.write('/mydir', None, dir=True)

        try:
            yield from client.write('/mydir', None, dir=True)
            assert False
        except aio_etcd.EtcdNotFile:
            pass
        try:
            yield from client.write('/mydir', None, dir=True, prevExist=False)
            assert False
        except aio_etcd.EtcdAlreadyExist:
            pass
示例#18
0
    def test_test_and_set(loop, self):
        """ INTEGRATION: try test_and_set operation """
        client = aio_etcd.Client(port=6281, loop=loop)

        set_result = yield from client.set('/test-key', 'old-test-value')

        set_result = yield from client.test_and_set(
            '/test-key',
            'test-value',
            'old-test-value',
            )

        try:
            yield from client.test_and_set('/test-key', 'new-value', 'old-test-value')
        except ValueError:
            pass
示例#19
0
    def test_get_set_unauthenticated(loop, self):
        """ INTEGRATION: set/get a new value unauthenticated (http->https) """

        client = aio_etcd.Client(port=6281, loop=loop)

        # See above for the reason of this change
        try:
            yield from client.set('/test_set', 'test-key')
            assert False
        except aio_etcd.EtcdException:
            pass
        try:
            yield from client.get('/test_set')
            assert False
        except aio_etcd.EtcdException:
            pass
示例#20
0
    def test_get_set_unauthenticated_with_ca(loop, self):
        """ INTEGRATION: try unauthenticated with validation (https->https)"""
        client = aio_etcd.Client(
            protocol='https', port=6281, ca_cert=self.ca2_cert_path, loop=loop)

        loop = asyncio.get_event_loop()
        try:
            yield from client.set('/test-set', 'test-key')
            assert False
        except aio_etcd.EtcdConnectionFailed:
            pass
        try:
            yield from client.get('/test-set')
            assert False
        except aio_etcd.EtcdConnectionFailed:
            pass
示例#21
0
    def test_watch_generator(loop, self):
        """ INTEGRATION: Receive a watch event from other process (gen) """

        client = aio_etcd.Client(port=6281, allow_reconnect=True, loop=loop)
        set_result = yield from client.set('/test-key', 'test-value')

        queue = asyncio.Queue(loop=loop)

        @asyncio.coroutine
        def change_value(key):
            yield from asyncio.sleep(0.5, loop=loop)
            c = aio_etcd.Client(port=6281, loop=loop)
            for i in range(0, 3):
                yield from c.set(key, 'test-value%d' % i)
                yield from c.get(key)

        @asyncio.coroutine
        def watch_value(key, queue):
            c = aio_etcd.Client(port=6281, loop=loop)
            n = 0
            @asyncio.coroutine
            def qput(event):
                nonlocal n
                yield from queue.put(event.value)
                n += 1
                if n == 3:
                    raise aio_etcd.StopWatching
                
            yield from c.eternal_watch(key, qput)
            assert n == 3, n


        watcher = asyncio.async(watch_value('/test-key', queue), loop=loop)
        changer = asyncio.async(change_value('/test-key'), loop=loop)

        values = ['test-value0', 'test-value1', 'test-value2']
        for i in range(0, 3):
            value = yield from queue.get()
            log.debug("index: %d: %s" % (i, value))
            self.assertTrue(value in values)

        yield from asyncio.wait_for(watcher,timeout=5,loop=loop)
        yield from asyncio.wait_for(changer,timeout=5,loop=loop)
示例#22
0
    def test_reconnet_fails(loop, self):
        """ INTEGRATION: fails to reconnect if no available machines """
        self.processHelper.stop()
        # Start with three instances (0, 1, 2)
        self.processHelper.run(number=3)
        # Connect to instance 0
        yield from asyncio.sleep(0.2,loop=loop)
        client = aio_etcd.Client(port=6281, allow_reconnect=True, loop=loop)
        set_result = yield from client.set('/test_set', 'test-key1')

        get_result = yield from client.get('/test_set')
        self.assertEquals('test-key1', get_result.value)
        self.processHelper.kill_one(2)
        self.processHelper.kill_one(1)
        self.processHelper.kill_one(0)
        try:
            yield from client.get('/test_set')
        except aio_etcd.EtcdException:
            pass
示例#23
0
    def test_get_set_unauthenticated(loop, self):
        """ INTEGRATION: set/get a new value unauthenticated (http->https) """

        client = aio_etcd.Client(port=6281, loop=loop)

        # Since python 3 raises a MaxRetryError here, this gets caught in
        # different code blocks in python 2 and python 3, thus messages are
        # different. Python 3 does the right thing(TM), for the record
        try:
            yield from client.set('/test_set', 'test-key')
            raise False
        except aio_etcd.EtcdException:
            pass

        try:
            yield from client.get('/test_set')
            assert False
        except aio_etcd.EtcdException:
            pass
示例#24
0
    def test_write_and_delete(loop, self):
        # Create an user
        u = auth.EtcdUser(self.client, 'test_user')
        u.roles.add('guest')
        u.roles.add('root')
        # directly from my suitcase
        u.password = '******'
        try:
            yield from u.write()
        except:
            self.fail("creating a user doesn't work")
        # Password gets wiped
        self.assertEquals(u.password, None)
        yield from u.read()
        # Verify we can log in as this user and access the auth (it has the
        # root role)
        cl = etcd.Client(port=6281, username='******', password='******')
        ul = auth.EtcdUser(cl, 'root')
        try:
            yield from ul.read()
        except etcd.EtcdInsufficientPermissions:
            self.fail("Reading auth with the new user is not possible")

        self.assertEquals(u.name, "test_user")
        self.assertEquals(u.roles, set(['guest', 'root']))

        # Unauthorized access is properly handled
        ua = auth.EtcdUser(self.unauth_client, 'test_user')
        with raises(etcd.EtcdInsufficientPermissions):
            yield from ua.write()

        # now let's test deletion
        du = auth.EtcdUser(self.client, 'user.does.not.exist')
        with raises(etcd.EtcdKeyNotFound):
            yield from du.delete()

        # Delete test_user
        yield from u.delete()
        with raises(etcd.EtcdKeyNotFound):
            yield from u.read()
        # Permissions are properly handled
        with raises(etcd.EtcdInsufficientPermissions):
            yield from ua.delete()
示例#25
0
    def test_watch_indexed_generator(loop, self):
        """ INTEGRATION: Receive a watch event from other process, ixd, (2) """

        client = aio_etcd.Client(port=6281, allow_reconnect=True, loop=loop)

        set_result = yield from client.set('/test-key', 'test-value')
        set_result = yield from client.set('/test-key', 'test-value0')
        original_index = int(set_result.modifiedIndex)
        set_result = yield from client.set('/test-key', 'test-value1')
        set_result = yield from client.set('/test-key', 'test-value2')

        queue = asyncio.Queue(loop=loop)

        @asyncio.coroutine
        def change_value(key, newValue):
            c = aio_etcd.Client(port=6281, loop=loop)
            yield from c.set(key, newValue)

        @asyncio.coroutine
        def watch_value(key, index, queue):
            c = aio_etcd.Client(port=6281, loop=loop)
            n = 0
            @asyncio.coroutine
            def qput(v):
                nonlocal n
                yield from queue.put(v.value)
                n += 1
                if n == 3:
                    raise aio_etcd.StopWatching
            yield from c.eternal_watch(key, qput, index=index)
            assert n == 3, n

        watcher = asyncio.async(watch_value('/test-key', original_index, queue), loop=loop)
        yield from asyncio.sleep(0.5, loop=loop)
        proc = asyncio.async(change_value('/test-key', 'test-value3',), loop=loop)

        for i in range(0, 3):
            value = yield from queue.get()
            log.debug("index: %d: %s" % (i, value))
            self.assertEquals('test-value%d' % i, value)

        yield from asyncio.wait_for(watcher,timeout=5,loop=loop)
        yield from asyncio.wait_for(proc,timeout=5,loop=loop)
示例#26
0
    def test_reconnect_with_several_hosts_passed(loop, self):
        """ INTEGRATION: receive several hosts at connection setup. """
        self.processHelper.stop()
        self.processHelper.run(number=3)
        yield from asyncio.sleep(0.2,loop=loop)
        client = aio_etcd.Client(
            host=(
                ('127.0.0.1', 6004),
                ('127.0.0.1', 6281)),
            allow_reconnect=True, loop=loop)
        set_result = yield from client.set('/test_set', 'test-key1')
        get_result = yield from client.get('/test_set')

        self.assertEquals('test-key1', get_result.value)

        self.processHelper.kill_one(0)

        get_result = yield from client.get('/test_set')
        self.assertEquals('test-key1', get_result.value)
示例#27
0
    def test_get_set_authenticated(loop, self):
        """ INTEGRATION: connecting to server with mutual auth """
        # This gives an unexplicable ssl error, as connecting to the same
        # Etcd cluster where this fails with the exact same code this
        # doesn't fail

        client = aio_etcd.Client(
            port=6281,
            protocol='https',
            cert=self.client_all_cert,
            ca_cert=self.ca_cert_path,
            loop=loop,
            )

        set_result = yield from client.set('/test_set', 'test-key')
        self.assertEquals(u'set', set_result.action.lower())
        self.assertEquals(u'/test_set', set_result.key)
        self.assertEquals(u'test-key', set_result.value)
        get_result = yield from client.get('/test_set')
        self.assertEquals('get', get_result.action.lower())
        self.assertEquals('/test_set', get_result.key)
        self.assertEquals('test-key', get_result.value)
示例#28
0
 def _connect(self):
     """Return an etcd client"""
     # Get sync client receiver
     while True:
         try:
             etcd_client = etcd.Client(self.host,
                                       self.port,
                                       allow_reconnect=True)
             # Test connection
             etcd_client.cluster_version  # pylint: disable=W0104
             # Save client
             self.sync_client = etcd_client
             break
         except (etcd.EtcdConnectionFailed,
                 urllib3.exceptions.MaxRetryError, etcd.EtcdException):
             self.logger.warning(
                 "Can not connect to etcd server, retrying in 5 seconds")
             time.sleep(5)
     # Get sync client sender
     while True:
         try:
             etcd_sender = etcd.Client(self.host,
                                       self.port,
                                       allow_reconnect=True)
             # Test connection
             etcd_sender.cluster_version  # pylint: disable=W0104
             # Save client
             self.sync_sender = etcd_sender
             break
         except (etcd.EtcdConnectionFailed,
                 urllib3.exceptions.MaxRetryError, etcd.EtcdException):
             self.logger.warning(
                 "Can not connect to etcd server, retrying in 5 seconds")
             time.sleep(5)
     # Get async etcd client
     self.async_client = aio_etcd.Client(self.host,
                                         self.port,
                                         allow_reconnect=True)
示例#29
0
    def test_watch_indexed(loop, self):
        """ INTEGRATION: Receive a watch event from other process, indexed """

        client = aio_etcd.Client(port=6281, allow_reconnect=True, loop=loop)

        set_result = yield from client.set('/test-key', 'test-value')
        set_result = yield from client.set('/test-key', 'test-value0')
        original_index = int(set_result.modifiedIndex)
        set_result = yield from client.set('/test-key', 'test-value1')
        set_result = yield from client.set('/test-key', 'test-value2')

        queue = asyncio.Queue(loop=loop)

        @asyncio.coroutine
        def change_value(key, newValue):
            c = aio_etcd.Client(port=6281, loop=loop)
            yield from c.set(key, newValue)
            yield from c.get(key)

        @asyncio.coroutine
        def watch_value(key, index, queue):
            c = aio_etcd.Client(port=6281, loop=loop)
            for i in range(0, 3):
                yield from queue.put((yield from c.watch(key, index=index + i)).value)


        watcher = asyncio.async(watch_value('/test-key', original_index, queue), loop=loop)
        yield from asyncio.sleep(0.5, loop=loop)
        proc = asyncio.async(change_value('/test-key', 'test-value3'), loop=loop)

        for i in range(0, 3):
            value = yield from queue.get()
            log.debug("index: %d: %s" % (i, value))
            self.assertEquals('test-value%d' % i, value)

        yield from asyncio.wait_for(watcher,timeout=5,loop=loop)
        yield from asyncio.wait_for(proc,timeout=5,loop=loop)
示例#30
0
 def create_client(self):
     return etcd.Client(self.host, self.port)