Esempio n. 1
0
 def __init__(self, path='/'):
     self.path = path
     zk_client =  KazooClient(hosts=ZOOKEEPER_SERVERS, read_only=True, timeout=TIMEOUT)
     try:
         zk_client.start()
         self.data, stat = zk_client.get(path)
         self.stat = _convert_stat(stat)
         self.children = zk_client.get_children(path) or []
         self.acls = _convert_acls(zk_client.get_acls(path)[0])
     finally:
         zk_client.stop()
Esempio n. 2
0
class ZKClient(object):
    def __init__(self, servers, timeout):
        self.connected = False
        print("Connecting to %s" % (servers))
        self.zk_client = KazooClient(hosts=servers)
        self.zk_client.start(timeout=timeout)

    def close(self):
        self.zk_client.stop()

    def get(self, path, watcher=None):
        return self.zk_client.get(path, watcher)

    def get_children(self, path, watcher=None):
        return self.zk_client.get_children(path, watcher)

    def get_acls(self, path):
        return self.zk_client.get_acls(path)
Esempio n. 3
0
class ZKClient(object):
    def __init__(self, servers, timeout):
        self.connected = False
        print("Connecting to %s" % (servers))
        self.zk_client = KazooClient(hosts=servers)
        self.zk_client.start(timeout=timeout)

    def close(self):
        self.zk_client.stop()

    def get(self, path, watcher=None):
        return self.zk_client.get(path, watcher)

    def get_children(self, path, watcher=None):
        return self.zk_client.get_children(path, watcher)

    def get_acls(self, path):
        return self.zk_client.get_acls(path)
Esempio n. 4
0
class ZooKeeper(object):

    def __init__(self, hosts, user=None, password=None):
        self._zookeeper = KazooClient(hosts=hosts)
        self._zookeeper.start()

        if user and password:
            self._zookeeper.add_auth('digest', '{}:{}'.format(user, password))

    def stop(self):
        if self._zookeeper:
            self._zookeeper.stop()
            self._zookeeper.close()
            self._zookeeper = None

    def list(self, path):
        try:
            return self._zookeeper.get_children(path)
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except NoAuthError:
            raise ZooKeeperException("No access to list node: {}".format(path))

    def get(self, path):
        try:
            value, _ = self._zookeeper.get(path)
            if value:
                value = value.decode('utf-8')
            else:
                value = ""

            return value
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except NoAuthError:
            raise ZooKeeperException("No access to get node: {}".format(path))

    def set(self, path, data):
        try:
            self._zookeeper.set(path, data.encode())
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except NoAuthError:
            raise ZooKeeperException("No access to set data on node: {}".format(path))

    def create(self, path, data=None, ephemeral=False, sequence=False, makepath=False):
        if data:
            data = data.encode()
        else:
            data = b""

        try:
            self._zookeeper.create(path,
                                   value=data,
                                   ephemeral=ephemeral,
                                   sequence=sequence,
                                   makepath=makepath)
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except NodeExistsError:
            raise ZooKeeperException("Node already exists: {}".format(path))
        except NoAuthError:
            raise ZooKeeperException("No access to create node: {}".format(path))

    def delete(self, path, recursive=False):
        try:
            self._zookeeper.delete(path, recursive=recursive)
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except NotEmptyError:
            raise ZooKeeperException("Node contains sub-nodes")
        except NoAuthError:
            raise ZooKeeperException("No access to delete node: {}".format(path))

    def stat(self, path):
        try:
            _, stat = self._zookeeper.get(path)
            return stat
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))

    def get_acl(self, path):
        try:
            acl, _ = self._zookeeper.get_acls(path)
            return acl
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))

    def add_acl(self, path, permissions, scheme, id):
        perms = get_permissions(permissions)

        if scheme == "digest":
            username, password = id.split(":")
            acl = make_digest_acl(username, password, **perms)
        else:
            acl = make_acl(scheme, id, **perms)

        current_acls = self.get_acl(path)
        current_acls.append(acl)

        try:
            self._zookeeper.set_acls(path, current_acls)
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except InvalidACLError as exc:
            raise ZooKeeperException("Invalid ACL format: {}".format(str(exc)))
        except NoAuthError:
            raise ZooKeeperException("No access to add acl on node: {}".format(path))

    def delete_acl(self, path, index):
        current_acls = self.get_acl(path)
        deleted = current_acls.pop(index)

        try:
            self._zookeeper.set_acls(path, current_acls)
        except NoNodeError:
            raise ZooKeeperException("No such node: {}".format(path))
        except NoAuthError:
            raise ZooKeeperException("No access to delete acl from node: {}".format(path))

        return deleted
Esempio n. 5
0
    def test_init_hierarchy(self):

        auth = ('digest', 'aa', 'pw_aa')
        hosts = '127.0.0.1:21811'
        users = {'aa': 'pw_aa', 'bb': 'pw_bb', 'cc': 'pw_cc'}
        hierarchy = {
            'node1': {
                '__val__': 'node1_val',
                '__acl__': {
                    'aa': 'cdrwa',
                    'bb': 'rw'
                },
                'node11': {
                    '__val__': 'node11_val',
                    '__acl__': {
                        'aa': 'cdrwa',
                        'cc': 'r'
                    },
                },
                'node12': {
                    '__val__': 'node12_val',
                    'node121': {
                        '__val__': 'node121_val'
                    }
                },
                'node13': {
                    '__acl__': {
                        'aa': 'cdrwa'
                    }
                }
            },
            'node2': {
                '__val__': 'node2_val',
                'node21': {
                    '__val__': 'node21_val'
                },
                'node22': {
                    '__acl__': {
                        'aa': 'rwa'
                    }
                }
            },
            'node3': {
                '__acl__': {
                    'aa': 'carw',
                    'cc': 'r'
                },
                'node31': {
                    'node311': {
                        'node3111': {},
                        'node3112': {}
                    }
                }
            }
        }

        zkutil.init_hierarchy(hosts, hierarchy, users, auth)

        zkcli = KazooClient(hosts)
        zkcli.start()
        zkcli.add_auth('digest', 'aa:pw_aa')

        expected_nodes = (
            ('/node1', '"node1_val"', [('digest', 'aa', 'cdrwa'),
                                       ('digest', 'bb', 'rw')],
             set(['node11', 'node12', 'node13'])),
            ('/node1/node11', '"node11_val"', [('digest', 'aa', 'cdrwa'),
                                               ('digest', 'cc', 'r')],
             set([])),
            ('/node1/node12', '"node12_val"', [('digest', 'aa', 'cdrwa'),
                                               ('digest', 'bb', 'rw')],
             set(['node121'])),
            ('/node1/node12/node121', '"node121_val"',
             [('digest', 'aa', 'cdrwa'), ('digest', 'bb', 'rw')], set([])),
            ('/node1/node13', '{}', [('digest', 'aa', 'cdrwa')], set([])),
            ('/node2', '"node2_val"', [('world', 'anyone', 'cdrwa')],
             set(['node21', 'node22'])),
            ('/node2/node21', '"node21_val"', [('world', 'anyone', 'cdrwa')],
             set([])),
            ('/node2/node22', '{}', [('digest', 'aa', 'rwa')], set([])),
            ('/node3', '{}', [('digest', 'aa', 'rwca'),
                              ('digest', 'cc', 'r')], set(['node31'])),
            ('/node3/node31', '{}', [('digest', 'aa', 'rwca'),
                                     ('digest', 'cc', 'r')], set(['node311'])),
            ('/node3/node31/node311', '{}', [('digest', 'aa', 'rwca'),
                                             ('digest', 'cc', 'r')],
             set(['node3111', 'node3112'])),
            ('/node3/node31/node311/node3111', '{}', [('digest', 'aa', 'rwca'),
                                                      ('digest', 'cc', 'r')],
             set([])),
            ('/node3/node31/node311/node3112', '{}', [('digest', 'aa', 'rwca'),
                                                      ('digest', 'cc', 'r')],
             set([])),
        )

        for node, val, acl, children in expected_nodes:

            actual_acl = zkutil.parse_kazoo_acl(zkcli.get_acls(node)[0])
            self.assertEqual(val, zkcli.get(node)[0])
            self.assertEqual(acl, actual_acl)
            self.assertEqual(children, set(zkcli.get_children(node)))

        zkcli.stop()
Esempio n. 6
0
class TestZKLock(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        utdocker.pull_image(zk_test_tag)

    def setUp(self):

        config.zk_acl = zk_test_acl
        config.zk_auth = zk_test_auth

        self.counter = 0
        self.running = True

        utdocker.create_network()
        utdocker.start_container(
            zk_test_name,
            zk_test_tag,
            env={
                "ZOO_MY_ID": 1,
                "ZOO_SERVERS": "server.1=0.0.0.0:2888:3888",
            },
            port_bindings={
                2181: 21811,
            }
        )

        self.zk = KazooClient(hosts='127.0.0.1:21811')
        self.zk.start()
        scheme, name, passw = zk_test_auth
        self.zk.add_auth(scheme, name + ':' + passw)

        # create lock base dir
        acl = zkutil.make_kazoo_digest_acl(zk_test_acl)
        self.zk.create('lock/', acl=acl)

        self.lck = zkutil.ZKLock('foo_name', zkclient=self.zk)

    def tearDown(self):

        self.zk.stop()
        utdocker.remove_container(zk_test_name)

    def _on_conn_change(self, state):

        self.lsn_count += 1

    def test_bounded_listener(self):

        # ensure that adding a bounded listener(self.on_xxx) is ok

        self.lsn_count = 0

        self.zk.add_listener(self._on_conn_change)
        self.zk.add_listener(self._on_conn_change)

        self.zk.stop()

        self.assertEqual(1, self.lsn_count)

    def _loop_acquire(self, n, ident):

        zk = KazooClient(hosts='127.0.0.1:21811')
        zk.start()
        scheme, name, passw = zk_test_auth
        zk.add_auth(scheme, name + ':' + passw)

        for ii in range(n):
            l = zkutil.ZKLock('foo_name', zkclient=zk)
            with l:

                self.total += 1
                self.counter += 1

                self.assertTrue(self.counter == 1)

                time.sleep(0.01)
                self.counter -= 1

                dd("id={ident:0>2} n={ii:0>2} got and released lock: {holder}".format(
                    ident=ident,
                    ii=ii,
                    holder=l.lock_holder))

        zk.stop()

    def test_concurrent(self):

        self.running = True
        self.total = 0
        n_repeat = 40
        n_thread = 5

        ths = []
        for ii in range(n_thread):
            t = threadutil.start_daemon_thread(self._loop_acquire, args=(n_repeat, ii,))
            ths.append(t)

        for th in ths:
            th.join()

        self.running = False
        self.assertEqual(n_repeat * n_thread, self.total)

    def test_persistent(self):
        l = zkutil.ZKLock('foo_name', ephemeral=False, on_lost=lambda: True)
        try:
            with l:
                l.zkclient.stop()
        except ConnectionClosedError:
            pass

        self.assertRaises(zkutil.LockTimeout, self.lck.acquire, timeout=0.2)

    def test_timeout(self):

        l1 = zkutil.ZKLock('foo_name', on_lost=lambda: True)
        l2 = zkutil.ZKLock('foo_name', on_lost=lambda: True)

        with l1:
            with ututil.Timer() as t:
                self.assertRaises(zkutil.LockTimeout, l2.acquire, timeout=0.2)
                self.assertAlmostEqual(0.2, t.spent(), places=1)

            with ututil.Timer() as t:
                self.assertRaises(zkutil.LockTimeout, l2.acquire, timeout=-1)
                self.assertAlmostEqual(0.0, t.spent(), delta=0.01)

        try:
            l2.acquire(timeout=-1)
        except zkutil.LockTimeout:
            self.fail('timeout<0 should could acquire')

    def test_lock_holder(self):
        a = zkutil.ZKLock('foo_name', on_lost=lambda: True)
        b = zkutil.ZKLock('foo_name', on_lost=lambda: True)

        with a:
            self.assertEqual((a.identifier, 0), a.lock_holder)
            val, zstate = self.zk.get(a.lock_path)
            self.assertEqual((val, zstate.version), a.lock_holder)

            locked, holder, ver = b.try_acquire()
            self.assertFalse(locked)
            self.assertEqual((a.identifier, 0), (holder, ver))
            self.assertEqual((val, zstate.version), (holder, ver))

    def test_watch_acquire(self):

        a = zkutil.ZKLock('foo', on_lost=lambda: True)
        b = zkutil.ZKLock('foo', on_lost=lambda: True)

        # no one locked

        n = 0
        for holder, ver in a.acquire_loop():
            n += 1
        self.assertEqual(0, n, 'acquired directly')

        # watch node change

        it = b.acquire_loop()

        holder, ver = it.next()
        self.assertEqual((a.identifier, 0), (holder, ver))

        self.zk.set(a.lock_path, 'xx')
        holder, ver = it.next()
        self.assertEqual(('xx', 1), (holder, ver), 'watched node change')

        a.release()
        try:
            holder, ver = it.next()
            self.fail('should not have next yield')
        except StopIteration:
            pass

        self.assertTrue(b.is_locked())

    def test_try_lock(self):

        l1 = zkutil.ZKLock('foo_name', on_lost=lambda: True)
        l2 = zkutil.ZKLock('foo_name', on_lost=lambda: True)

        with l1:
            with ututil.Timer() as t:
                locked, holder, ver = l2.try_acquire()
                self.assertFalse(locked)
                self.assertEqual(l1.identifier, holder)
                self.assertGreaterEqual(ver, 0)

                self.assertAlmostEqual(0.0, t.spent(), delta=0.05)

        with ututil.Timer() as t:
            locked, holder, ver = l2.try_acquire()
            self.assertTrue(locked)
            self.assertEqual(l2.identifier, holder)
            self.assertEqual(ver, 0)

            self.assertAlmostEqual(0.0, t.spent(), delta=0.05)

    def test_try_release(self):

        l1 = zkutil.ZKLock('foo_name', on_lost=lambda: True)
        l2 = zkutil.ZKLock('foo_name', on_lost=lambda: True)

        released, holder, ver = l1.try_release()
        self.assertEqual((True, l1.identifier, -1), (released, holder, ver))

        with l2:
            released, holder, ver = l1.try_release()
            self.assertEqual((False, l2.identifier, 0), (released, holder, ver))

            released, holder, ver = l2.try_release()
            self.assertEqual((True, l2.identifier, 0), (released, holder, ver))

    def test_zk_lost(self):

        sess = {'acquired': True}

        def watch(state):
            dd('zk node state changed to: ', state)
            sess['acquired'] = False

        self.zk.add_listener(watch)

        # test zk close

        l = zkutil.ZKLock('foo_name', zkclient=self.zk)

        l.acquire()
        self.zk.stop()
        time.sleep(0.1)
        self.assertFalse(sess['acquired'])

        # test node delete

        sess['acquired'] = True
        self.zk.start()
        self.zk.add_listener(watch)

        l = zkutil.ZKLock('foo_name', zkclient=self.zk)

        with l:
            time.sleep(0.1)
            self.zk.delete(l.zkconf.lock('foo_name'))
            time.sleep(0.1)
            self.assertFalse(sess['acquired'])

    def test_node_change_after_acquired(self):

        sess = {'acquired': True}

        def on_lost():
            sess['acquired'] = False

        l = zkutil.ZKLock('foo_name',
                          zkclient=self.zk,
                          on_lost=on_lost)

        with l:
            sess['acquired'] = True
            self.zk.delete(l.zkconf.lock('foo_name'))
            time.sleep(0.1)
            self.assertFalse(sess['acquired'])

        l = zkutil.ZKLock('foo_name',
                          zkclient=self.zk,
                          on_lost=on_lost)

        with l:
            sess['acquired'] = True
            self.zk.set(l.zkconf.lock('foo_name'), 'xxx')
            time.sleep(0.1)
            self.assertFalse(sess['acquired'])

    def test_node_change_after_released(self):

        sess = {'acquired': True}

        def on_lost():
            sess['acquired'] = False

        l = zkutil.ZKLock('foo_name',
                          zkclient=self.zk,
                          on_lost=on_lost)

        with l:
            sess['acquired'] = True

        time.sleep(0.1)
        self.assertTrue(sess['acquired'])

    def test_is_locked(self):

        l = zkutil.ZKLock('foo_name', zkclient=self.zk)

        with l:
            pass

        self.assertFalse(l.is_locked())

        l = zkutil.ZKLock('foo_name', zkclient=self.zk)
        l.acquire()
        self.assertTrue(l.is_locked())
        l.try_release()
        self.assertFalse(l.is_locked())

    def test_conn_lost_when_blocking_acquiring(self):

        l2 = zkutil.ZKLock('foo_name', on_lost=lambda: True)

        th = threadutil.start_daemon(target=self.zk.stop, after=0.5)
        with l2:
            try:
                self.lck.acquire(timeout=1)
                self.fail('expected connection error')
            except ConnectionClosedError:
                pass

        th.join()

    def test_internal_zkclient(self):

        sess = {'acquired': True}

        def on_lost():
            sess['acquired'] = False

        # There must be a listener specified to watch connection issue
        self.assertRaises(ValueError, zkutil.ZKLock, 'foo_name')

        l = zkutil.ZKLock('foo_name', on_lost=on_lost)

        with l:
            self.zk.delete(l.zkconf.lock('foo_name'))
            time.sleep(0.1)
            self.assertFalse(sess['acquired'])

    def test_acl(self):
        with self.lck:
            acls, zstat = self.zk.get_acls(self.lck.lock_path)

        dd(acls)
        self.assertEqual(1, len(acls))

        acl = acls[0]
        expected = zkutil.perm_to_long(zk_test_acl[0][2], lower=False)

        self.assertEqual(set(expected), set(acl.acl_list))
        self.assertEqual('digest', acl.id.scheme)
        self.assertEqual(zk_test_acl[0][0], acl.id.id.split(':')[0])

    def test_config(self):

        old = (config.zk_acl, config.zk_auth, config.zk_node_id)

        config.zk_acl = (('foo', 'bar', 'cd'),
                         ('xp', '123', 'cdrwa'))

        config.zk_auth = ('digest', 'xp', '123')
        config.zk_node_id = 'abc'

        l = zkutil.ZKLock('foo_name', on_lost=lambda: True)

        dd(l.zkconf.acl())

        def _check_ac(ac):
            self.assertEqual('digest', ac.id.scheme)
            self.assertEqual('foo', ac.id.id.split(':')[0])
            self.assertEqual(set(['CREATE', 'DELETE']), set(ac.acl_list))

        _check_ac(l.zkconf.kazoo_digest_acl()[0])

        with l:
            # should have created lock node
            data, zstate = self.zk.get(l.lock_path)
            dd(data)

            self.assertEqual('abc', data.split('-')[0])

            acls, zstate = self.zk.get_acls(l.lock_path)
            dd(acls)

            _check_ac(acls[0])

        (config.zk_acl, config.zk_auth, config.zk_node_id) = old

    def test_hosts(self):

        l = zkutil.ZKLock('foo_name',
                          zkconf=dict(
                              hosts='127.0.0.1:21811',
                          ),
                          on_lost=lambda: True)

        with l:
            self.assertEqual('127.0.0.1:21811', l._hosts)

    def test_specify_identifier(self):

        a = zkutil.ZKLock('foo_name',
                          zkconf=dict(
                              hosts='127.0.0.1:21811',
                          ),
                          identifier='faked',
                          on_lost=lambda: True)

        b = zkutil.ZKLock('foo_name',
                          zkconf=dict(
                              hosts='127.0.0.1:21811',
                          ),
                          identifier='faked',
                          on_lost=lambda: True)

        a.acquire()
        b.acquire()
        dd('a and b has the same identifier thus they both can acquire the lock')

    def test_release_listener_removed(self):

        self.lck.release()
        self.assertNotIn(self.lck.on_connection_change, self.zk.state_listeners)

    def test_release_owning_client_stopped(self):

        l = zkutil.ZKLock('foo_name',
                          zkconf=dict(
                              hosts='127.0.0.1:21811',
                          ),
                          on_lost=lambda: True)

        l.release()
        self.assertTrue(l.zkclient._stopped.is_set())
    def test_init_hierarchy(self):

        auth = ('digest', 'aa', 'pw_aa')
        hosts = '127.0.0.1:21811'
        users = {'aa': 'pw_aa', 'bb': 'pw_bb', 'cc': 'pw_cc'}
        hierarchy = {
            'node1':
            {
                '__val__': 'node1_val',
                '__acl__': {'aa': 'cdrwa', 'bb': 'rw'},
                'node11':
                {
                    '__val__': 'node11_val',
                    '__acl__': {'aa': 'cdrwa', 'cc': 'r'},
                },
                'node12':
                {
                    '__val__': 'node12_val',
                    'node121': {'__val__': 'node121_val'}
                },
                'node13':
                {
                    '__acl__': {'aa': 'cdrwa'}
                }
            },
            'node2':
            {
                '__val__': 'node2_val',
                'node21': {'__val__': 'node21_val'},
                'node22': {'__acl__': {'aa': 'rwa'}}
            },
            'node3':
            {
                '__acl__': {'aa': 'carw', 'cc': 'r'},
                'node31': {'node311': {'node3111': {}, 'node3112': {}}}
            }
        }

        zkutil.init_hierarchy(hosts, hierarchy, users, auth)

        zkcli = KazooClient(hosts)
        zkcli.start()
        zkcli.add_auth('digest', 'aa:pw_aa')

        expected_nodes = (
            ('/node1', '"node1_val"', [('digest', 'aa', 'cdrwa'),
                                       ('digest', 'bb', 'rw')], set(['node11', 'node12', 'node13'])),
            ('/node1/node11', '"node11_val"',
             [('digest', 'aa', 'cdrwa'), ('digest', 'cc', 'r')], set([])),
            ('/node1/node12', '"node12_val"',
             [('digest', 'aa', 'cdrwa'), ('digest', 'bb', 'rw')], set(['node121'])),
            ('/node1/node12/node121', '"node121_val"',
             [('digest', 'aa', 'cdrwa'), ('digest', 'bb', 'rw')], set([])),
            ('/node1/node13', '{}', [('digest', 'aa', 'cdrwa')], set([])),

            ('/node2', '"node2_val"',
             [('world', 'anyone', 'cdrwa')], set(['node21', 'node22'])),
            ('/node2/node21', '"node21_val"',
             [('world', 'anyone', 'cdrwa')],  set([])),
            ('/node2/node22', '{}', [('digest', 'aa', 'rwa')],  set([])),

            ('/node3', '{}', [('digest', 'aa', 'rwca'),
                              ('digest', 'cc', 'r')], set(['node31'])),
            ('/node3/node31', '{}', [('digest', 'aa', 'rwca'),
                                     ('digest', 'cc', 'r')],  set(['node311'])),
            ('/node3/node31/node311', '{}',
             [('digest', 'aa', 'rwca'), ('digest', 'cc', 'r')], set(['node3111', 'node3112'])),
            ('/node3/node31/node311/node3111', '{}',
             [('digest', 'aa', 'rwca'), ('digest', 'cc', 'r')], set([])),
            ('/node3/node31/node311/node3112', '{}',
             [('digest', 'aa', 'rwca'), ('digest', 'cc', 'r')], set([])),
        )

        for node, val, acl, children in expected_nodes:

            actual_acl = zkutil.parse_kazoo_acl(zkcli.get_acls(node)[0])
            self.assertEqual(val, zkcli.get(node)[0])
            self.assertEqual(acl, actual_acl)
            self.assertEqual(children, set(zkcli.get_children(node)))

        zkcli.stop()
Esempio n. 8
0
class WebWindow(object):
	def setupUi(self, Window):
		Window.setObjectName("Window")
		self.centralwidget = QtWidgets.QWidget(Window)
		self.centralwidget.setObjectName("centralwidget")
		self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
		self.verticalLayout.setContentsMargins(0, 0, 0, 0)
		self.verticalLayout.setObjectName("verticalLayout")
		self.zk = None
		self.webView = QtWebKitWidgets.QWebView(self.centralwidget)
		self.webView.setObjectName("webView")
		self.webView.setRenderHint(QPainter.Antialiasing, True)
		self.webView.setRenderHint(QPainter.TextAntialiasing, True)
		self.webView.setRenderHint(QPainter.SmoothPixmapTransform, True)
		self.webView.setRenderHint(QPainter.HighQualityAntialiasing, True)
		self.webView.setPage(WebPage())
		frame = self.webView.page().mainFrame()
		frame.javaScriptWindowObjectCleared.connect(self.initJsComm)
		self.verticalLayout.addWidget(self.webView)
		Window.setCentralWidget(self.centralwidget)
		self.retranslateUi(Window)
		QtCore.QMetaObject.connectSlotsByName(Window)
		self.loadDefaultAcl()
	def retranslateUi(self, Window):
		_translate = QtCore.QCoreApplication.translate
		Window.setWindowTitle(_translate("Window", "Zookeeper GUI"))
	def loadLocalFile(self, filename):
		localdir = os.path.abspath(sys.path[0])
		if os.path.isfile(localdir):
			localdir = os.path.dirname(localdir)
		self.webView.setUrl( QtCore.QUrl.fromLocalFile(localdir+'/'+filename) )
	def getCfgVar(self, name):
		localdir = os.path.abspath(sys.path[0])
		if os.path.isfile(localdir):
			localdir = os.path.dirname(localdir)
		cfg = {}
		obj = None
		try:
			obj = open(localdir+'/cfg.json','r')
			cfg = json.loads(obj.read())
		except Exception as e:
			logging.info(str(e))
		finally:
			if obj is not None:
				obj.close()
		if name in cfg:
			return str(cfg[name])
		return ''
	def setCfgVar(self, name, value):
		localdir = os.path.abspath(sys.path[0])
		if os.path.isfile(localdir):
			localdir = os.path.dirname(localdir)
		cfg = {}
		obj = None
		try:
			obj = open(localdir+'/cfg.json','r')
			cfg = json.loads(obj.read())
		except Exception as e:
			pass
		finally:
			if obj is not None:
				obj.close()
		cfg[name] = value
		obj = None
		try:
			obj = open(localdir+'/cfg.json','w')
			obj.truncate()
			obj.write(json.dumps(cfg))
		except Exception as e:
			logging.info(str(e))
		finally:
			if obj is not None:
				obj.close()
	def makeDigestCred(self, user, plain_pass):
		m = hashlib.sha1( bytes(user,'utf8') + b':' + bytes(plain_pass,'utf8') ).digest()
		return user+':'+base64.b64encode(m).strip().decode('utf8')
	def initJsComm(self):
		frame = self.webView.page().mainFrame()
		frame.addToJavaScriptWindowObject('py',self)
	@pyqtSlot(str)
	def jsSetWinTitle(self, title):
		_translate = QtCore.QCoreApplication.translate
		self.setWindowTitle(_translate("Window", title))
	@pyqtSlot(str, result=str)
	def jsCheckYaml(self, s):
		try:
			a = yaml.load(s)
		except Exception as e:
			return str(e)
		if a is None:
			return 'Failed'
		return ''
	@pyqtSlot(str,result=str)
	def jsGetCfg(self, name):
		return self.getCfgVar(name)
	@pyqtSlot(str,str)
	def jsSetCfg(self, name, value):
		self.setCfgVar(name, value)
	def loadDefaultAcl(self):
		self.updateDefaultAclCache( self.getCfgVar('defaultacl') )
	def updateDefaultAclCache(self, list_str):
		if list_str is not None and len(list_str)>0:
			cache = json.loads(list_str)
			self.default_acl_plain = []
			self.default_acl = []
			for one in cache:
				if(one['scheme']=='world'):
					self.default_acl_plain.append(one)
					acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('world', 'anyone') )
					self.default_acl.append(acl)
				elif(one['scheme']=='digest'):
					self.default_acl_plain.append(one)
					if 'id' in one:
						acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('digest', one['id']) )
					else:
						acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('digest', self.makeDigestCred(one['user'],one['pass'])) )
					self.default_acl.append(acl)
				elif(one['scheme']=='ip'):
					self.default_acl_plain.append(one)
					acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('ip', one['ip']) )
					self.default_acl.append(acl)
		else:
			self.default_acl_plain = []
			self.default_acl = None
	@pyqtSlot(str,result=str)
	def jsSetDefaultAcl(self, list_str):
		self.updateDefaultAclCache(list_str)
		self.setCfgVar('defaultacl', json.dumps(self.default_acl_plain))
	@pyqtSlot(result=str)
	def jsGetDefaultAcl(self):
		return json.dumps(self.default_acl_plain)
	@pyqtSlot()
	def jsGetZk(self):
		return self.zk
	@pyqtSlot(result=int)
	def jsZkIsConnected(self):
		if self.zk is not None:
			return int(self.zk.state=='CONNECTED')
		return 0
	@pyqtSlot(str, str, result=str)
	def jsZkConnect(self,host, auth_list_str):
		try:
			if self.zk is not None:
				#self.zk.remove_listener(self.onZkStateChange)
				self.zk.stop()
				self.zk.close()
			self.zk = KazooClient(hosts=host)
			#self.zk.add_listener(self.onZkStateChange)
			self.zk.start(15)
			auth_list = json.loads(auth_list_str)
			for one in auth_list:
				cred = self.makeDigestCred(one['user'], one['pass'])
				self.zk.add_auth('digest', one['user']+':'+one['pass'])
		except Exception as e:
			logging.error("jsZkConnect, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	#def onZkStateChange(self,state):
	#	frame = self.webView.page().mainFrame()
	#	frame.evaluateJavaScript("onPyZkStateChange('"+state+"')")
	@pyqtSlot(str, result=QVariant)
	def jsZkGetChildren(self, path):
		try:
			logging.info("jsZkGetChildren, path="+path)
			children = self.zk.get_children(path)
		except NoNodeError:
			logging.error("jsZkGetChildren, NoNodeError")
			return QVariant({"err":"node not exists"})
		except Exception as e:
			logging.error("jsZkGetChildren, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return QVariant({"err":str(e)+', traceback='+str(strlist)})
		return QVariant({"err":"", "children":children})
	@pyqtSlot(str, result=QVariant)
	def jsZkGet(self, path):
		try:
			logging.info("jsZkGet, path="+path)
			ret = self.zk.get(path)
		except NoNodeError:
			logging.error("jsZkGet, NoNodeError")
			return QVariant({"err":"node not exists"})
		except Exception as e:
			logging.error("jsZkGet, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return QVariant({"err":str(e)+', traceback='+str(strlist)})
		ctime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ret[1].ctime/1000))
		mtime = time.strftime('%Y-%m-%d %H:%M:%S', time.localtime(ret[1].mtime/1000))
		stat = {'ctime':ctime,'mtime':mtime,'version':ret[1].version}
		data = ''
		if ret[0] is not None:
			data = ret[0].decode('utf8')
		else:
			logging.info('jsZkGet data None, path='+path)
		return QVariant({"err":"", "data":data, "stat":QVariant(stat)})
	@pyqtSlot(str, str, int, result=str)
	def jsZkSet(self, path, data, ver):
		try:
			logging.info("jsZkSet, path="+path+',ver='+str(ver))
			self.zk.set(path, bytes(data, 'utf8'),ver)
		except NoNodeError as e:
			logging.error("jsZkSet, NoNodeError")
			return "node not exists"
		except BadVersionError as e:
			logging.error("jsZkSet, BadVersionError")
			return "bad version"
		except Exception as e:
			logging.error("jsZkSet, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	@pyqtSlot(str, result=QVariant)
	def jsZkGetAcl(self, path):
		try:
			logging.info("jsZkGetAcl, path="+path)
			ret = self.zk.get_acls(path)
		except NoNodeError as e:
			logging.error("jsZkGetAcl, NoNodeError")
			return QVariant({"err":"node not exists"})
		except Exception as e:
			logging.error("jsZkGetAcl, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return QVariant({"err":str(e)+', traceback='+str(strlist)})
		lst = []
		for acl in ret[0]:
			dacl = {"perm":acl.perms,'scheme':acl.id.scheme,'id':acl.id.id}
			lst.append(QVariant(dacl))
		stat = {'ctime':ret[1].ctime,'mtime':ret[1].mtime,'version':ret[1].version}
		return QVariant({"err":"", "acl_list":QVariant(lst), "stat":QVariant(stat)})
	@pyqtSlot(str, str, result=str)
	def jsZkSetAcl(self, path, list_str):
		try:
			acl_list = None
			if list_str is not None and len(list_str)>0:
				cache = json.loads(list_str)
				acl_list = []
				for one in cache:
					if(one['scheme']=='world'):
						acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('world', 'anyone') )
						acl_list.append(acl)
					elif(one['scheme']=='digest'):
						if 'id' in one:
							acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('digest', one['id']) )
						else:
							acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('digest', self.makeDigestCred(one['user'],one['pass'])) )
						acl_list.append(acl)
					elif(one['scheme']=='ip'):
						acl = kazoo.security.ACL( one['perm'], kazoo.security.Id('ip', one['ip']) )
						acl_list.append(acl)
			self.zk.set_acls(path, acl_list)
		except NoNodeError as e:
			logging.error("jsZkSetAcl, NoNodeError")
			return "node not exists"
		except InvalidACLError as e:
			logging.error("jsZkSetAcl, InvalidACLError")
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return "invalid acl, traceback: "+str(strlist)
		except BadVersionError as e:
			logging.error("jsZkSetAcl, BadVersionError")
			return "bad version error"
		except Exception as e:
			logging.error("jsZkSetAcl, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	@pyqtSlot(str,str,int,int,result=str)
	def jsZkCreate(self, path, data, ephem, seq):
		try:
			logging.info("jsZkCreate, path="+path)
			self.zk.create(path=path, value=bytes(data,'utf8'), ephemeral=bool(ephem), sequence=bool(seq))
			if self.default_acl is not None and len(self.default_acl)>0:
				self.zk.set_acls(path, self.default_acl)
		except NoNodeError as e:
			logging.error("jsZkCreate, NoNodeError")
			return "node not exists"
		except NodeExistsError as e:
			logging.error("jsZkCreate, NodeExistsError")
			return "node already exists"
		except NoChildrenForEphemeralsError as e:
			logging.error("jsZkCreate, NoChildrenForEphemeralsError")
			return "ephemeral node can not have child"
		except Exception as e:
			logging.error("jsZkCreate, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	@pyqtSlot(str, int, int, result=str)
	def jsZkDelete(self, path, ver, recursive):
		try:
			logging.info("jsZkDelete, path="+path+',ver='+str(ver)+', recursive='+str(recursive))
			self.zk.delete(path, ver, bool(recursive))
		except NoNodeError as e:
			logging.error("jsZkDelete, NoNodeError")
			return "node not exists"
		except BadVersionError as e:
			logging.error("jsZkDelete, BadVersionError")
			return "bad version"
		except NotEmptyError as e:
			logging.error("jsZkDelete, NotEmptyError")
			return "node not empty"
		except Exception as e:
			logging.error("jsZkDelete, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	@pyqtSlot(str, str, int, int, result=str)
	def jsZkCopy(self, dest_path, ori_path, max_depth, children_only):
		logging.info("jsZkCopy, dest_path="+dest_path+", ori_path="+ori_path+", children_only="+str(children_only))
		#copy node first
		if children_only==0:
			try:
				ori_data = self.zk.get(ori_path)
				if self.zk.exists(dest_path) is None:
					self.zk.create(dest_path, ori_data[0], acl=self.default_acl)
				else:
					self.zk.set(dest_path, ori_data[0])
			except NoNodeError as e:
				logging.error("jsZkCopy, node, NoNodeError, ori_path="+ori_path+', dest_path='+dest_path)
				return "node not exists"
			except Exception as e:
				logging.error("jsZkCopy, "+str(e))
				t,v,tb = sys.exc_info()
				strlist = traceback.format_tb(tb)
				return str(e)+', traceback='+str(strlist)
		#copy children
		path = ''
		try:
			max_depth -= 1
			path = ori_path
			ori_children = self.zk.get_children(ori_path)
			for child in ori_children:
				path = ori_path+'/'+child
				ret = self.jsZkCopy(dest_path+'/'+child, ori_path+'/'+child, max_depth, 0)
				if isinstance(ret, QVariant):
					return ret
				elif len(ret)>0:
					return ret
		except NoNodeError as e:
			logging.error("jsZkCopy, child, NoNodeError")
			return "node not exists, path="+path
		except Exception as e:
			logging.error("jsZkCopy, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	'''
	@pyqtSlot(str, str, int, result=str)
	def jsZkCopyChildren(self, dest_path, ori_path, max_depth):
		path = ''
		try:
			max_depth -= 1;
			logging.info("jsZkCopyChildren, dest_path="+dest_path+", ori_path="+ori_path)
			path = ori_path
			ori_children = self.zk.get_children(ori_path)
			path = dest_path
			dest_children = self.zk.get_children(dest_path)
			for child in ori_children:
				if child in dest_children:
					return 'child ['+child+'] is found in both path'
			for child in ori_children:
				path = ori_path+'/'+child
				data = self.zk.get(path)[0]
				path = dest_path+'/'+child
				self.zk.create(path, data, acl=self.default_acl)
				if max_depth>0:
					ret = self.jsZkCopyChildren(dest_path+'/'+child, ori_path+'/'+child, max_depth)
					if len(ret)>0:
						return ret
		except NoNodeError as e:
			logging.info("jsZkCopyChildren, NoNodeError")
			return "node not exists, path="+path
		except ZookeeperError as e:
			logging.info("jsZkCopyChildren, ZookeeperError")
			return str(e)+', path='+path
		return ''
	'''
	@pyqtSlot(str, int, result=str)
	def jsZkDeleteChildren(self, main_path, max_depth):
		path = ''
		try:
			max_depth -= 1
			path = main_path
			logging.info("jsZkDeleteChildren, path="+main_path)
			children = self.zk.get_children(path)
			for child in children:
				path = main_path+'/'+child
				if max_depth>0:
					ret = self.jsZkDeleteChildren(path, max_depth)
					if len(ret)>0:
						return ret
				self.zk.delete(path)
		except NoNodeError as e:
			logging.error("jsZkDeleteChildren, NoNodeError")
			return "node not exists, path="+path
		except Exception as e:
			logging.error("jsZkDeleteChildren, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	@pyqtSlot(str, str, int, int, result=str)
	def jsZkExport(self, local_dir, main_path, max_depth, without_acl):
		path = ''
		try:
			max_depth -= 1
			path = main_path
			logging.info("jsZkExport, path="+main_path+' to local dir '+local_dir)
			data = self.zk.get(main_path)
			p = pathlib.Path(local_dir)
			if not p.exists():
				p.mkdir(parents=True)
			elif not p.is_dir():
				return 'local '+local_dir+' exists, but not a directory'
			for child in p.iterdir():
				return 'local path '+local_dir+' is not empty, clear it first'
			p = pathlib.Path(local_dir+'/____data')
			p.touch()
			obj = open(str(p),'wb')
			try:
				if data[0] is not None:
					obj.write(data[0])
			finally:
				obj.close()
			if not without_acl:
				ret = self.zk.get_acls(path)
				lst = []
				if ret is not None:
					for acl in ret[0]:
						lst.append( {"perm":acl.perms,'scheme':acl.id.scheme,'id':acl.id.id} )
				p = pathlib.Path(local_dir+'/____acl')
				p.touch()
				obj = open(str(p),'w')
				try:
					obj.write(json.dumps(lst))
				finally:
					obj.close()
			children = self.zk.get_children(path)
			if children is not None:
				for child in children:
					if child=='zookeeper':
						continue
					path = main_path+'/'+child
					if max_depth>0:
						ret = self.jsZkExport(local_dir+'/'+child, path, max_depth, without_acl)
						if len(ret)>0:
							return ret
		except NoNodeError as e:
			logging.error("jsZkExport, NoNodeError")
			return "node not exists, path="+path
		except Exception as e:
			logging.error("jsZkExport, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''
	@pyqtSlot(str, str, int, int, result=str)
	def jsZkImport(self, local_dir, main_path, max_depth, without_acl):
		path = ''
		try:
			max_depth -= 1
			path = main_path
			logging.info("jsZkImport, path="+main_path+' from local dir '+local_dir)
			obj = open(local_dir+'/____data', 'rb')
			if self.zk.exists(path) is None:
				self.zk.create(path, obj.read(), acl=self.default_acl)
			else:
				self.zk.set(path, obj.read())
			if not without_acl:
				obj = open(local_dir+'/____acl', 'r')
				acl_list = None
				list_str = obj.read()
				if list_str is not None and len(list_str)>0:
					cache = json.loads(list_str)
					acl_list = []
					for one in cache:
						acl = kazoo.security.ACL( one['perm'], kazoo.security.Id(one['scheme'], one['id']) )
						acl_list.append(acl)
					self.zk.set_acls(path, acl_list)
			p = pathlib.Path(local_dir)
			for child in p.iterdir():
				if not child.is_dir():
					continue
				if child.name=='zookeeper':
					continue
				ret = self.jsZkImport(str(child), path+'/'+child.name, max_depth, without_acl)
				if len(ret)>0:
					return ret
		except NoNodeError as e:
			logging.error("jsZkImport, NoNodeError")
			return "node not exists, path="+path
		except Exception as e:
			logging.error("jsZkImport, "+str(e))
			t,v,tb = sys.exc_info()
			strlist = traceback.format_tb(tb)
			return str(e)+', traceback='+str(strlist)
		return ''