from kazoo.client import KazooClient from kazoo.security import ACL, make_acl client = KazooClient(hosts='127.0.0.1:2181') try: client.start() # world auth digest ip scheme = '' # anyone # addauth digest user:pwd # username:base64 # ID = '' # r = client.add_auth('digest', 'xjj:123456') # print(r, type(r)) r = client.set_acls('/a', [make_acl('auth', 'xyj:123123', all=True)]) # r = client.get_acls('/a') print(r, type(r), len(r)) finally: client.stop()
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
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 ''