├── .gitignore
├── LICENSE
├── README.md
├── bin
└── syncdb.py
├── conf
├── __init__.py
├── conf.yml
├── init_settings.py
└── settings.py
├── docs
└── images
│ ├── zkdash_conf.jpg
│ ├── zkdash_search.jpg
│ ├── zkdash_snapshot.jpg
│ └── zkdash_zookeeper.jpg
├── handler
├── __init__.py
├── api
│ ├── __init__.py
│ └── v1
│ │ ├── __init__.py
│ │ └── feedback.py
├── auth
│ ├── __init__.py
│ └── index.py
├── bases
│ ├── __init__.py
│ ├── api_base.py
│ ├── base.py
│ └── common_base.py
└── config
│ ├── __init__.py
│ ├── agent.py
│ ├── snapshot.py
│ ├── znode.py
│ └── zookeeper.py
├── init.py
├── lib
├── __init__.py
├── db
│ ├── __init__.py
│ ├── database.py
│ └── retrydb.py
├── excel
│ ├── __init__.py
│ └── excel.py
├── uimethods
│ └── __init__.py
├── uimodule
│ ├── __init__.py
│ ├── paginate.py
│ └── query.py
├── utils
│ ├── __init__.py
│ ├── logger.py
│ ├── pyshell.py
│ └── routes.py
└── zyqconf
│ ├── README.rst
│ ├── __init__.py
│ ├── hooks.py
│ ├── qconf_py.so
│ └── types.py
├── model
├── __init__.py
└── db
│ ├── __init__.py
│ ├── base.py
│ ├── zd_qconf_agent.py
│ ├── zd_qconf_feedback.py
│ ├── zd_snapshot.py
│ ├── zd_snapshot_tree.py
│ ├── zd_znode.py
│ └── zd_zookeeper.py
├── requirements.txt
├── service
├── __init__.py
├── snapshot.py
├── znode.py
└── zookeeper.py
├── static
├── BJUI
│ ├── js
│ │ ├── bjui-ajax.js
│ │ ├── bjui-ajaxtab.js
│ │ ├── bjui-alertmsg.js
│ │ ├── bjui-all.js
│ │ ├── bjui-basedrag.js
│ │ ├── bjui-contextmenu.js
│ │ ├── bjui-core.js
│ │ ├── bjui-datagrid.js
│ │ ├── bjui-datepicker.js
│ │ ├── bjui-dialog.js
│ │ ├── bjui-extends.js
│ │ ├── bjui-frag.js
│ │ ├── bjui-initui.js
│ │ ├── bjui-lookup.js
│ │ ├── bjui-navtab.js
│ │ ├── bjui-pagination.js
│ │ ├── bjui-plugins.js
│ │ ├── bjui-regional.zh-CN.js
│ │ ├── bjui-slidebar.js
│ │ ├── bjui-spinner.js
│ │ ├── bjui-tabledit.js
│ │ ├── bjui-tablefixed.js
│ │ ├── bjui-tags.js
│ │ ├── bjui-taskbar.js
│ │ ├── bjui-theme.js
│ │ ├── bjui-upload.js
│ │ ├── bjui-util.date.js
│ │ ├── jquery-1.7.2.min.js
│ │ ├── jquery.cookie.js
│ │ ├── minify.sh
│ │ └── yuicompressor-2.4.8.jar
│ ├── other
│ │ ├── html5shiv.min.js
│ │ ├── jquery.iframe-transport.js
│ │ └── respond.min.js
│ ├── plugins
│ │ ├── bootstrap.js
│ │ ├── bootstrap.min.js
│ │ ├── bootstrapSelect
│ │ │ ├── bootstrap-select.css
│ │ │ ├── bootstrap-select.css.map
│ │ │ ├── bootstrap-select.js
│ │ │ ├── bootstrap-select.js.map
│ │ │ ├── bootstrap-select.min.js
│ │ │ ├── defaults-zh_CN.js
│ │ │ └── defaults-zh_CN.min.js
│ │ ├── colorpicker
│ │ │ ├── css
│ │ │ │ ├── bootstrap-colorpicker.css
│ │ │ │ └── bootstrap-colorpicker.min.css
│ │ │ ├── img
│ │ │ │ └── bootstrap-colorpicker
│ │ │ │ │ ├── alpha-horizontal.png
│ │ │ │ │ ├── alpha.png
│ │ │ │ │ ├── hue-horizontal.png
│ │ │ │ │ ├── hue.png
│ │ │ │ │ └── saturation.png
│ │ │ └── js
│ │ │ │ ├── bootstrap-colorpicker.js
│ │ │ │ └── bootstrap-colorpicker.min.js
│ │ ├── download
│ │ │ └── jquery.fileDownload.js
│ │ ├── dragsort
│ │ │ ├── jquery.dragsort-0.5.1.js
│ │ │ └── jquery.dragsort-0.5.1.min.js
│ │ ├── echarts
│ │ │ ├── chart
│ │ │ │ ├── bar.js
│ │ │ │ ├── chord.js
│ │ │ │ ├── eventRiver.js
│ │ │ │ ├── force.js
│ │ │ │ ├── funnel.js
│ │ │ │ ├── gauge.js
│ │ │ │ ├── k.js
│ │ │ │ ├── line.js
│ │ │ │ ├── map.js
│ │ │ │ ├── pie.js
│ │ │ │ ├── radar.js
│ │ │ │ └── scatter.js
│ │ │ ├── echarts.js
│ │ │ └── theme
│ │ │ │ ├── blue.js
│ │ │ │ ├── dark.js
│ │ │ │ ├── default.js
│ │ │ │ ├── gray.js
│ │ │ │ ├── green.js
│ │ │ │ ├── helianthus.js
│ │ │ │ ├── infographic.js
│ │ │ │ ├── macarons.js
│ │ │ │ ├── red.js
│ │ │ │ └── shine.js
│ │ ├── highcharts
│ │ │ ├── adapters
│ │ │ │ └── standalone-framework.js
│ │ │ ├── highcharts-3d.js
│ │ │ ├── highcharts-all.js
│ │ │ ├── highcharts-more.js
│ │ │ ├── highcharts.js
│ │ │ ├── modules
│ │ │ │ ├── canvas-tools.js
│ │ │ │ ├── data.js
│ │ │ │ ├── drilldown.js
│ │ │ │ ├── exporting.js
│ │ │ │ ├── funnel.js
│ │ │ │ ├── heatmap.js
│ │ │ │ ├── no-data-to-display.js
│ │ │ │ └── solid-gauge.js
│ │ │ └── themes
│ │ │ │ ├── dark-blue.js
│ │ │ │ ├── dark-green.js
│ │ │ │ ├── dark-unica.js
│ │ │ │ ├── gray.js
│ │ │ │ ├── grid-light.js
│ │ │ │ ├── grid.js
│ │ │ │ ├── sand-signika.js
│ │ │ │ └── skies.js
│ │ ├── icheck
│ │ │ ├── icheck.js
│ │ │ └── icheck.min.js
│ │ ├── kindeditor_4.1.10
│ │ │ ├── attached
│ │ │ │ └── test.txt
│ │ │ ├── editor-content.css
│ │ │ ├── kindeditor-all-min.js
│ │ │ ├── kindeditor-all.js
│ │ │ ├── kindeditor-all.min.js
│ │ │ ├── kindeditor-min.js
│ │ │ ├── kindeditor.js
│ │ │ ├── lang
│ │ │ │ ├── ar.js
│ │ │ │ ├── en.js
│ │ │ │ ├── ko.js
│ │ │ │ ├── zh_CN.js
│ │ │ │ └── zh_TW.js
│ │ │ ├── license.txt
│ │ │ ├── php
│ │ │ │ ├── JSON.php
│ │ │ │ ├── demo.php
│ │ │ │ ├── file_manager_json.php
│ │ │ │ └── upload_json.php
│ │ │ ├── plugins
│ │ │ │ ├── anchor
│ │ │ │ │ └── anchor.js
│ │ │ │ ├── autoheight
│ │ │ │ │ └── autoheight.js
│ │ │ │ ├── baidumap
│ │ │ │ │ ├── baidumap.js
│ │ │ │ │ ├── index.html
│ │ │ │ │ └── map.html
│ │ │ │ ├── clearhtml
│ │ │ │ │ └── clearhtml.js
│ │ │ │ ├── code
│ │ │ │ │ ├── code.js
│ │ │ │ │ ├── prettify.css
│ │ │ │ │ └── prettify.js
│ │ │ │ ├── emoticons
│ │ │ │ │ ├── emoticons.js
│ │ │ │ │ └── images
│ │ │ │ │ │ ├── 0.gif
│ │ │ │ │ │ ├── 1.gif
│ │ │ │ │ │ ├── 10.gif
│ │ │ │ │ │ ├── 100.gif
│ │ │ │ │ │ ├── 101.gif
│ │ │ │ │ │ ├── 102.gif
│ │ │ │ │ │ ├── 103.gif
│ │ │ │ │ │ ├── 104.gif
│ │ │ │ │ │ ├── 105.gif
│ │ │ │ │ │ ├── 106.gif
│ │ │ │ │ │ ├── 107.gif
│ │ │ │ │ │ ├── 108.gif
│ │ │ │ │ │ ├── 109.gif
│ │ │ │ │ │ ├── 11.gif
│ │ │ │ │ │ ├── 110.gif
│ │ │ │ │ │ ├── 111.gif
│ │ │ │ │ │ ├── 112.gif
│ │ │ │ │ │ ├── 113.gif
│ │ │ │ │ │ ├── 114.gif
│ │ │ │ │ │ ├── 115.gif
│ │ │ │ │ │ ├── 116.gif
│ │ │ │ │ │ ├── 117.gif
│ │ │ │ │ │ ├── 118.gif
│ │ │ │ │ │ ├── 119.gif
│ │ │ │ │ │ ├── 12.gif
│ │ │ │ │ │ ├── 120.gif
│ │ │ │ │ │ ├── 121.gif
│ │ │ │ │ │ ├── 122.gif
│ │ │ │ │ │ ├── 123.gif
│ │ │ │ │ │ ├── 124.gif
│ │ │ │ │ │ ├── 125.gif
│ │ │ │ │ │ ├── 126.gif
│ │ │ │ │ │ ├── 127.gif
│ │ │ │ │ │ ├── 128.gif
│ │ │ │ │ │ ├── 129.gif
│ │ │ │ │ │ ├── 13.gif
│ │ │ │ │ │ ├── 130.gif
│ │ │ │ │ │ ├── 131.gif
│ │ │ │ │ │ ├── 132.gif
│ │ │ │ │ │ ├── 133.gif
│ │ │ │ │ │ ├── 134.gif
│ │ │ │ │ │ ├── 14.gif
│ │ │ │ │ │ ├── 15.gif
│ │ │ │ │ │ ├── 16.gif
│ │ │ │ │ │ ├── 17.gif
│ │ │ │ │ │ ├── 18.gif
│ │ │ │ │ │ ├── 19.gif
│ │ │ │ │ │ ├── 2.gif
│ │ │ │ │ │ ├── 20.gif
│ │ │ │ │ │ ├── 21.gif
│ │ │ │ │ │ ├── 22.gif
│ │ │ │ │ │ ├── 23.gif
│ │ │ │ │ │ ├── 24.gif
│ │ │ │ │ │ ├── 25.gif
│ │ │ │ │ │ ├── 26.gif
│ │ │ │ │ │ ├── 27.gif
│ │ │ │ │ │ ├── 28.gif
│ │ │ │ │ │ ├── 29.gif
│ │ │ │ │ │ ├── 3.gif
│ │ │ │ │ │ ├── 30.gif
│ │ │ │ │ │ ├── 31.gif
│ │ │ │ │ │ ├── 32.gif
│ │ │ │ │ │ ├── 33.gif
│ │ │ │ │ │ ├── 34.gif
│ │ │ │ │ │ ├── 35.gif
│ │ │ │ │ │ ├── 36.gif
│ │ │ │ │ │ ├── 37.gif
│ │ │ │ │ │ ├── 38.gif
│ │ │ │ │ │ ├── 39.gif
│ │ │ │ │ │ ├── 4.gif
│ │ │ │ │ │ ├── 40.gif
│ │ │ │ │ │ ├── 41.gif
│ │ │ │ │ │ ├── 42.gif
│ │ │ │ │ │ ├── 43.gif
│ │ │ │ │ │ ├── 44.gif
│ │ │ │ │ │ ├── 45.gif
│ │ │ │ │ │ ├── 46.gif
│ │ │ │ │ │ ├── 47.gif
│ │ │ │ │ │ ├── 48.gif
│ │ │ │ │ │ ├── 49.gif
│ │ │ │ │ │ ├── 5.gif
│ │ │ │ │ │ ├── 50.gif
│ │ │ │ │ │ ├── 51.gif
│ │ │ │ │ │ ├── 52.gif
│ │ │ │ │ │ ├── 53.gif
│ │ │ │ │ │ ├── 54.gif
│ │ │ │ │ │ ├── 55.gif
│ │ │ │ │ │ ├── 56.gif
│ │ │ │ │ │ ├── 57.gif
│ │ │ │ │ │ ├── 58.gif
│ │ │ │ │ │ ├── 59.gif
│ │ │ │ │ │ ├── 6.gif
│ │ │ │ │ │ ├── 60.gif
│ │ │ │ │ │ ├── 61.gif
│ │ │ │ │ │ ├── 62.gif
│ │ │ │ │ │ ├── 63.gif
│ │ │ │ │ │ ├── 64.gif
│ │ │ │ │ │ ├── 65.gif
│ │ │ │ │ │ ├── 66.gif
│ │ │ │ │ │ ├── 67.gif
│ │ │ │ │ │ ├── 68.gif
│ │ │ │ │ │ ├── 69.gif
│ │ │ │ │ │ ├── 7.gif
│ │ │ │ │ │ ├── 70.gif
│ │ │ │ │ │ ├── 71.gif
│ │ │ │ │ │ ├── 72.gif
│ │ │ │ │ │ ├── 73.gif
│ │ │ │ │ │ ├── 74.gif
│ │ │ │ │ │ ├── 75.gif
│ │ │ │ │ │ ├── 76.gif
│ │ │ │ │ │ ├── 77.gif
│ │ │ │ │ │ ├── 78.gif
│ │ │ │ │ │ ├── 79.gif
│ │ │ │ │ │ ├── 8.gif
│ │ │ │ │ │ ├── 80.gif
│ │ │ │ │ │ ├── 81.gif
│ │ │ │ │ │ ├── 82.gif
│ │ │ │ │ │ ├── 83.gif
│ │ │ │ │ │ ├── 84.gif
│ │ │ │ │ │ ├── 85.gif
│ │ │ │ │ │ ├── 86.gif
│ │ │ │ │ │ ├── 87.gif
│ │ │ │ │ │ ├── 88.gif
│ │ │ │ │ │ ├── 89.gif
│ │ │ │ │ │ ├── 9.gif
│ │ │ │ │ │ ├── 90.gif
│ │ │ │ │ │ ├── 91.gif
│ │ │ │ │ │ ├── 92.gif
│ │ │ │ │ │ ├── 93.gif
│ │ │ │ │ │ ├── 94.gif
│ │ │ │ │ │ ├── 95.gif
│ │ │ │ │ │ ├── 96.gif
│ │ │ │ │ │ ├── 97.gif
│ │ │ │ │ │ ├── 98.gif
│ │ │ │ │ │ ├── 99.gif
│ │ │ │ │ │ └── static.gif
│ │ │ │ ├── filemanager
│ │ │ │ │ ├── filemanager.js
│ │ │ │ │ └── images
│ │ │ │ │ │ ├── file-16.gif
│ │ │ │ │ │ ├── file-64.gif
│ │ │ │ │ │ ├── folder-16.gif
│ │ │ │ │ │ ├── folder-64.gif
│ │ │ │ │ │ └── go-up.gif
│ │ │ │ ├── flash
│ │ │ │ │ └── flash.js
│ │ │ │ ├── image
│ │ │ │ │ ├── image.js
│ │ │ │ │ └── images
│ │ │ │ │ │ ├── align_left.gif
│ │ │ │ │ │ ├── align_right.gif
│ │ │ │ │ │ ├── align_top.gif
│ │ │ │ │ │ └── refresh.png
│ │ │ │ ├── insertfile
│ │ │ │ │ └── insertfile.js
│ │ │ │ ├── lineheight
│ │ │ │ │ └── lineheight.js
│ │ │ │ ├── link
│ │ │ │ │ └── link.js
│ │ │ │ ├── map
│ │ │ │ │ ├── map.html
│ │ │ │ │ └── map.js
│ │ │ │ ├── media
│ │ │ │ │ └── media.js
│ │ │ │ ├── multiimage
│ │ │ │ │ ├── images
│ │ │ │ │ │ ├── image.png
│ │ │ │ │ │ ├── select-files-en.png
│ │ │ │ │ │ ├── select-files-zh_CN.png
│ │ │ │ │ │ └── swfupload.swf
│ │ │ │ │ └── multiimage.js
│ │ │ │ ├── pagebreak
│ │ │ │ │ └── pagebreak.js
│ │ │ │ ├── plainpaste
│ │ │ │ │ └── plainpaste.js
│ │ │ │ ├── preview
│ │ │ │ │ └── preview.js
│ │ │ │ ├── quickformat
│ │ │ │ │ └── quickformat.js
│ │ │ │ ├── table
│ │ │ │ │ └── table.js
│ │ │ │ ├── template
│ │ │ │ │ ├── html
│ │ │ │ │ │ ├── 1.html
│ │ │ │ │ │ ├── 2.html
│ │ │ │ │ │ └── 3.html
│ │ │ │ │ └── template.js
│ │ │ │ └── wordpaste
│ │ │ │ │ └── wordpaste.js
│ │ │ └── themes
│ │ │ │ ├── common
│ │ │ │ ├── anchor.gif
│ │ │ │ ├── blank.gif
│ │ │ │ ├── flash.gif
│ │ │ │ ├── loading.gif
│ │ │ │ ├── media.gif
│ │ │ │ └── rm.gif
│ │ │ │ ├── default
│ │ │ │ ├── background.png
│ │ │ │ ├── default.css
│ │ │ │ └── default.png
│ │ │ │ ├── qq
│ │ │ │ ├── editor.gif
│ │ │ │ └── qq.css
│ │ │ │ └── simple
│ │ │ │ └── simple.css
│ │ ├── niceValidator
│ │ │ ├── images
│ │ │ │ ├── loading.gif
│ │ │ │ ├── validator_default.png
│ │ │ │ └── validator_simple.png
│ │ │ ├── jquery.validator.css
│ │ │ ├── jquery.validator.js
│ │ │ ├── jquery.validator.themes.js
│ │ │ └── local
│ │ │ │ └── en.js
│ │ ├── other
│ │ │ ├── jquery.autosize.js
│ │ │ └── respond.js
│ │ ├── styles
│ │ │ └── zTreeStyle
│ │ │ │ ├── img
│ │ │ │ ├── diy
│ │ │ │ │ ├── 1_close.png
│ │ │ │ │ ├── 1_open.png
│ │ │ │ │ ├── 2.png
│ │ │ │ │ ├── 3.png
│ │ │ │ │ ├── 4.png
│ │ │ │ │ ├── 5.png
│ │ │ │ │ ├── 6.png
│ │ │ │ │ ├── 7.png
│ │ │ │ │ ├── 8.png
│ │ │ │ │ └── 9.png
│ │ │ │ ├── line_conn.gif
│ │ │ │ ├── loading.gif
│ │ │ │ ├── zTreeStandard.gif
│ │ │ │ └── zTreeStandard.png
│ │ │ │ └── zTreeStyle.css
│ │ ├── swfupload
│ │ │ ├── swfupload.js
│ │ │ └── swfupload.min.js
│ │ ├── uploadify
│ │ │ ├── css
│ │ │ │ └── uploadify.css
│ │ │ ├── img
│ │ │ │ ├── add.jpg
│ │ │ │ ├── cancel.jpg
│ │ │ │ ├── delete.jpg
│ │ │ │ ├── upload.jpg
│ │ │ │ └── uploadify-cancel.png
│ │ │ └── scripts
│ │ │ │ ├── jquery.uploadify.js
│ │ │ │ ├── jquery.uploadify.min.js
│ │ │ │ └── uploadify.swf
│ │ └── ztree
│ │ │ ├── jquery.ztree.all-3.5.js
│ │ │ ├── jquery.ztree.all-3.5.min.js
│ │ │ ├── jquery.ztree.core-3.5.js
│ │ │ ├── jquery.ztree.core-3.5.min.js
│ │ │ ├── jquery.ztree.excheck-3.5.js
│ │ │ ├── jquery.ztree.excheck-3.5.min.js
│ │ │ ├── jquery.ztree.exedit-3.5.js
│ │ │ ├── jquery.ztree.exedit-3.5.min.js
│ │ │ ├── jquery.ztree.exhide-3.5.js
│ │ │ └── jquery.ztree.exhide-3.5.min.js
│ └── themes
│ │ ├── blue
│ │ ├── core.css
│ │ ├── purple.png
│ │ ├── purple@2x.png
│ │ ├── topbg.png
│ │ └── zTreeStandard.png
│ │ ├── css
│ │ ├── FA
│ │ │ ├── css
│ │ │ │ ├── font-awesome.css
│ │ │ │ └── font-awesome.min.css
│ │ │ └── fonts
│ │ │ │ ├── FontAwesome.otf
│ │ │ │ ├── fontawesome-webfont.eot
│ │ │ │ ├── fontawesome-webfont.svg
│ │ │ │ ├── fontawesome-webfont.ttf
│ │ │ │ ├── fontawesome-webfont.woff
│ │ │ │ └── fontawesome-webfont.woff2
│ │ ├── bootstrap.css
│ │ ├── bootstrap.min.css
│ │ ├── ie7.css
│ │ ├── img
│ │ │ ├── changed-flag-icon.png
│ │ │ ├── diy
│ │ │ │ ├── 1_close.png
│ │ │ │ ├── 1_open.png
│ │ │ │ ├── 2.png
│ │ │ │ ├── 3.png
│ │ │ │ ├── 4.png
│ │ │ │ ├── 5.png
│ │ │ │ ├── 6.png
│ │ │ │ ├── 7.png
│ │ │ │ ├── 8.png
│ │ │ │ └── 9.png
│ │ │ ├── error-bg.png
│ │ │ ├── line_conn.gif
│ │ │ ├── line_conn.png
│ │ │ ├── loading.gif
│ │ │ └── logo.png
│ │ └── style.css
│ │ ├── default
│ │ ├── core.css
│ │ ├── purple.png
│ │ ├── purple@2x.png
│ │ ├── topbg.png
│ │ └── zTreeStandard.png
│ │ ├── fonts
│ │ ├── glyphicons-halflings-regular.eot
│ │ ├── glyphicons-halflings-regular.svg
│ │ ├── glyphicons-halflings-regular.ttf
│ │ └── glyphicons-halflings-regular.woff
│ │ ├── green
│ │ ├── core.css
│ │ ├── purple.png
│ │ ├── purple@2x.png
│ │ ├── topbg.png
│ │ └── zTreeStandard.png
│ │ ├── orange
│ │ ├── core.css
│ │ ├── purple.png
│ │ ├── purple@2x.png
│ │ ├── topbg.png
│ │ └── zTreeStandard.png
│ │ └── purple
│ │ ├── core.css
│ │ ├── purple.png
│ │ ├── purple@2x.png
│ │ ├── topbg.png
│ │ └── zTreeStandard.png
├── css
│ ├── admin.css
│ ├── base.css
│ ├── doc
│ │ └── doc.css
│ ├── style.css
│ └── table.css
├── images
│ ├── 001.jpg
│ ├── 002.jpg
│ ├── 003.jpg
│ ├── 004.jpg
│ ├── 005.jpg
│ ├── bjui-b.png
│ ├── bodybg.jpg
│ ├── btn.jpg
│ ├── captcha.jpeg
│ ├── domain_logo.png
│ ├── group.png
│ ├── inputbg.jpg
│ ├── loginbg_01.jpg
│ ├── loginbg_02.jpg
│ ├── loginbg_03.jpg
│ ├── loginbg_04.jpg
│ ├── loginbg_05.jpg
│ ├── loginbg_06.jpg
│ ├── loginbg_07.jpg
│ ├── loginbg_08.jpg
│ ├── loginbg_09.jpg
│ ├── loginbtnbg.jpg
│ ├── logo.jpg
│ ├── logo.png
│ ├── logo_bootstrap.png
│ ├── magage-bg.jpg
│ ├── magage-img.jpg
│ └── tablethbg.jpg
└── js
│ └── form_search.js
└── tpl
├── config
├── agent
│ ├── add.html
│ ├── datagrid.html
│ ├── edit.html
│ ├── index.html
│ └── watch.html
├── snapshot
│ ├── displaytree.html
│ ├── index.html
│ └── view.html
├── znode
│ ├── add.html
│ ├── batchedit.html
│ ├── displaytree.html
│ ├── edit.html
│ ├── index.html
│ ├── syncstatus.html
│ └── view.html
└── zookeeper
│ ├── add.html
│ ├── datagrid.html
│ ├── edit.html
│ ├── index.html
│ ├── stat.html
│ └── statdetail.html
├── error
└── error.html
├── index.html
└── uimodule
├── paginate.html
└── query.html
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
3 | *.swp
4 | *.swo
5 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # zkdash
2 |
3 | zkdash是一个zookeeper的管理界面,也可以作为任何基于zookeeper的配置管理项目比如:Qconf
4 |
5 | ## 开发规划
6 |
7 | zkdash目前正在开发第二版本,更易用,更开发,拥有完善权限管理,支持zk,更易用。
8 | 第二版已经在着手开源相关工作,会打造一个基于配置中心,服务发现,CICD,CMDB一体化的微服务管理平台。
9 |
10 | ### zkdash页面展示
11 |
12 | 
13 |
14 | 
15 |
16 | 
17 |
18 | 
19 |
20 |
21 | ### 安装与运行
22 | 安装步骤
23 |
24 | - 安装并运行mysql
25 |
26 | - 安装python2.7, 版本最好 >= 2.7.6
27 |
28 | - 下载zkdash `git clone https://github.com/ireaderlab/zkdash.git`
29 |
30 | - 安装依赖项
31 |
32 | ```
33 | cd zkdash
34 | pip install -r requirements.txt
35 | ```
36 |
37 | - 设置配置文件
38 |
39 | 根据需要修改当前目录下./conf/conf.yml中相关配置信息,配置文件详细说明见后面
40 |
41 | - 同步数据库表结构
42 | 首先创建数据库zkdash,并设置数据库的用户名和密码
43 | 将配置文件的数据库的用户名和密码进行修改
44 |
45 | ```
46 | DATABASE:
47 | db: 'zkdash'
48 | host: '192.168.1.1' # 修改为你的数据库地址
49 | port: 3306 # 设置端口号
50 | user: 'tokyo' # 修改用户名
51 | passwd: 'tokyo!' # 修改密码
52 | ```
53 |
54 | 设置完成后进行初始化数据库
55 |
56 | ```
57 | cd zkdash
58 | python ./bin/syncdb.py # 注意执行路径必须为./bin/syncdb.py
59 | ```
60 |
61 | 说明:数据库使用mysql,创建表结构前请先配置数据库连接信息
62 |
63 | - 运行
64 |
65 | ```
66 | cd zkdash
67 | python init.py -port=8888
68 | ```
69 |
70 | 说明:初次运行zkdash时需要到zookeeper管理菜单下增加监控的zookeeper集群ip信息
71 |
72 |
73 | ### 配置文件说明
74 |
75 | 配置文件详细说明
76 |
77 | 数据库配置项(DATABASE)
78 |
79 | - db: 数据库名称
80 | - host: ip地址
81 | - port: 端口号
82 | - user: 用户名
83 | - passwd: 密码
84 |
85 | 全局配置项
86 |
87 | - USE_QCONF: 是否通过QConf获取zookeeper数据(使用该项可以提高树形展示配置信息的响应速度)
88 |
89 |
90 | ### 与QConf的搭配使用
91 |
92 | - 反馈服务器地址:http://ip:port/api/v1/feedback(Agent同步状况查看依赖此反馈信息)
93 |
94 |
95 | ### 注意事项
96 | 1. 新增节点需要先指定父节点,并且只能逐级增加
97 | 2. 当设置使用QConf获取zookeeper数据时,zookeeper管理菜单下的zookeeper集群名称需要与QConf
98 | 客户端Agent配置文件的idc名称一致
99 |
--------------------------------------------------------------------------------
/bin/syncdb.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: syncdb.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-10-10
11 | '''
12 | # pylint: disable=import-error, unused-variable, protected-access
13 | import sys
14 | import os
15 | import pkgutil
16 | sys.path.append(os.path.dirname(os.path.split(os.path.realpath(__file__))[0]))
17 |
18 | import model.db
19 | from model.db.base import ZKDASH_DB
20 | from lib.utils import find_subclasses
21 |
22 |
23 | def sync_db():
24 | """sync db
25 | """
26 | # firstly, import all modules of model.db package
27 | prefix = model.db.__name__ + "."
28 | for importer, modname, ispkg in pkgutil.iter_modules(model.db.__path__, prefix):
29 | __import__(modname)
30 |
31 | # then, find all subclasses of WARSHIP_DB.Model
32 | models = find_subclasses(ZKDASH_DB.Model)
33 | for mod in models:
34 | if mod.table_exists():
35 | print "table exists: %s, drop it!" % mod._meta.db_table
36 | mod.drop_table()
37 | mod.create_table()
38 | print "created table: %s" % mod._meta.db_table
39 |
40 |
41 | if __name__ == '__main__':
42 | sync_db()
43 |
--------------------------------------------------------------------------------
/conf/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 | # pylint: disable=invalid-name
13 |
14 | # initailize log
15 | import logging
16 | log = logging.getLogger()
17 |
18 | # initialize conf.settings module which stores conf info
19 | import conf.init_settings
20 |
--------------------------------------------------------------------------------
/conf/conf.yml:
--------------------------------------------------------------------------------
1 | # database
2 | DATABASE:
3 | db: 'zkdash'
4 | host: '192.168.1.1'
5 | port: 3306
6 | user: 'tokyo'
7 | passwd: 'tokyo!'
8 |
9 | # 是否通过QConf获取zookeeper数据(使用该项需要在本地先运行QConf客户端agent)
10 | USE_QCONF: False
11 |
12 | # log conf
13 | LOG_ITEMS:
14 | - file: /data/logs/zkdash/zkdash.log
15 | log_levels:
16 | - DEBUG
17 | - INFO
18 | - WARNING
19 | - ERROR
20 | - CRITICAL
21 | format: '[%(levelname)s %(asctime)s %(filename)s %(lineno)d] %(message)s'
22 | when: 'midnight'
23 | interval: 1
24 | backup_count: 10
25 | backup_suffix: '%Y%m%d'
26 | level: 'DEBUG'
27 | - file: /data/logs/zkdash/zkdash.error.log
28 | log_levels:
29 | - WARNING
30 | - ERROR
31 | - CRITICAL
32 | format: '[%(levelname)s %(asctime)s %(filename)s %(lineno)d] %(message)s'
33 | when: 'midnight'
34 | interval: 1
35 | backup_count: 30
36 | backup_suffix: '%Y%m%d'
37 | level: 'DEBUG'
38 |
--------------------------------------------------------------------------------
/conf/init_settings.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2013,掌阅科技
6 | All rights reserved.
7 |
8 | File Name: init_settings.py
9 | Author: zhuangshixiong
10 | Created on: 2015-10-15
11 | '''
12 | import os
13 | import sys
14 | import imp
15 |
16 | import yaml
17 | import tornado
18 | from tornado.options import define, options
19 |
20 | define("port", default=8080, help="port to listen", type=int)
21 | define("debug", default=True, help="debug mode or not")
22 |
23 | tornado.options.parse_command_line()
24 |
25 | if options.debug:
26 | import tornado.autoreload
27 |
28 |
29 | def create_settings_module(file_name):
30 | """ create settings module from config file
31 | """
32 | conf_data = None
33 | with open(file_name, 'r') as conf_file:
34 | conf_data = yaml.load(conf_file)
35 | if not isinstance(conf_data, dict):
36 | raise Exception("config file not parsed correctly")
37 |
38 | module = imp.new_module('settings')
39 | module.__dict__.update(conf_data)
40 | module.__dict__.update({'OPTIONS': options})
41 | return module
42 |
43 |
44 | # 根据配置文件生成配置模块,供全局使用
45 | settings_module = create_settings_module('{}/conf/conf.yml'.format(os.getcwd()))
46 | sys.modules['conf.settings'] = settings_module
47 |
--------------------------------------------------------------------------------
/conf/settings.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | '''
4 | Copyright (c) 2014,掌阅科技
5 | All rights reserved.
6 |
7 | 摘 要: settings.py
8 | 创 建 者: zhuangshixiong
9 | 创建日期: 2015-09-23
10 | '''
11 |
12 |
13 | if __name__ == '__main__':
14 | pass
15 |
--------------------------------------------------------------------------------
/docs/images/zkdash_conf.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ireaderlab/zkdash/a9e27e9cc63dcfbb483a1fdfa00c98fd0b079739/docs/images/zkdash_conf.jpg
--------------------------------------------------------------------------------
/docs/images/zkdash_search.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ireaderlab/zkdash/a9e27e9cc63dcfbb483a1fdfa00c98fd0b079739/docs/images/zkdash_search.jpg
--------------------------------------------------------------------------------
/docs/images/zkdash_snapshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ireaderlab/zkdash/a9e27e9cc63dcfbb483a1fdfa00c98fd0b079739/docs/images/zkdash_snapshot.jpg
--------------------------------------------------------------------------------
/docs/images/zkdash_zookeeper.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ireaderlab/zkdash/a9e27e9cc63dcfbb483a1fdfa00c98fd0b079739/docs/images/zkdash_zookeeper.jpg
--------------------------------------------------------------------------------
/handler/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/handler/api/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/handler/api/v1/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/handler/api/v1/feedback.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: feedback.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-06-24
11 | """
12 | from datetime import datetime
13 |
14 | from handler.bases import ApiBaseHandler
15 | from handler.bases import ArgsMap
16 | from lib import route
17 | from model.db.zd_qconf_feedback import ZdQconfFeedback
18 |
19 |
20 | @route(r'/api/v1/feedback')
21 | class ZdQconfFeedbackSaveHandler(ApiBaseHandler):
22 | """save
23 | """
24 | args_list = [
25 | ArgsMap('id', default=''),
26 | ArgsMap('hostname', default=''),
27 | ArgsMap('ip', default=''),
28 | ArgsMap('node_whole', default=''),
29 | ArgsMap('value_md5', default=''),
30 | ArgsMap('idc', default=''),
31 | ArgsMap('update_time', default=''),
32 | ArgsMap('data_type', default=''),
33 | ArgsMap('deleted', default=''),
34 | ]
35 |
36 | def response(self):
37 | '''add
38 | '''
39 | feedback = ZdQconfFeedback.one(idc=self.idc, ip=self.ip, path=self.node_whole)
40 | if feedback is None:
41 | # create new feedback record
42 | feedback = ZdQconfFeedback()
43 | # 填充字段
44 | if self.idc:
45 | feedback.idc = self.idc
46 | if self.ip:
47 | feedback.ip = self.ip
48 | if self.hostname:
49 | feedback.hostname = self.hostname
50 | if self.node_whole:
51 | feedback.path = self.node_whole
52 | if self.value_md5:
53 | feedback.md5_value = self.value_md5
54 | if self.update_time:
55 | # convert unix timestamp to datetime
56 | update_time = datetime.fromtimestamp(
57 | int(self.update_time)).strftime('%Y-%m-%d %H:%M:%S')
58 | feedback.update_time = update_time
59 | if self.data_type:
60 | feedback.data_type = self.data_type
61 | # 自定义字段
62 | if self.deleted:
63 | feedback.deleted = self.deleted
64 | feedback.save()
65 | # qconf protocol, return '0' means ok
66 | self.finish('0')
67 |
--------------------------------------------------------------------------------
/handler/auth/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/handler/auth/index.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: index.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-10-09
11 | """
12 | from handler.bases import CommonBaseHandler
13 | from lib import route
14 |
15 |
16 | @route(r'/')
17 | class IndexHandler(CommonBaseHandler):
18 |
19 | '''配置管理系统页面入口
20 | '''
21 |
22 | def response(self):
23 | return self.render('index.html')
24 |
25 |
26 | @route(r'/auth/index/main', '首页')
27 | class IndexMainHandler(CommonBaseHandler):
28 |
29 | '''首页
30 | '''
31 |
32 | def response(self):
33 | self.finish()
34 |
--------------------------------------------------------------------------------
/handler/bases/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: base.py,2014-12-5日添加文件头文档
9 | 创 建 者: WangLichao
10 | 创建日期: 2014-12-5
11 | """
12 | from handler.bases.base import RestHandler
13 | from handler.bases.base import ArgsMap
14 | from handler.bases.common_base import CommonBaseHandler
15 | from handler.bases.api_base import ApiBaseHandler
16 |
--------------------------------------------------------------------------------
/handler/bases/api_base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: api_base.py
9 | 创 建 者: ZengDuju
10 | 创建日期: 2015-04-10
11 | '''
12 | from handler.bases import CommonBaseHandler
13 |
14 |
15 | class ApiBaseHandler(CommonBaseHandler):
16 | """ApiBaseHandler 不进行XSRF cookie检查
17 | """
18 |
19 | def check_xsrf_cookie(self):
20 | """重写check_xsrf_cookie
21 | """
22 | pass
23 |
--------------------------------------------------------------------------------
/handler/config/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-06-12
11 | '''
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/init.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: init.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2014-10-13
11 | '''
12 | import os
13 | # tornado
14 | import tornado.httpserver
15 | import tornado.ioloop
16 | # lib
17 | from lib import load
18 | from lib import uimodule, uimethods
19 | from lib.utils import logger
20 | from lib.utils import pyshell
21 | # conf
22 | from conf import log
23 | from conf.settings import (
24 | LOG_ITEMS,
25 | OPTIONS,
26 | )
27 |
28 |
29 | class Application(tornado.web.Application):
30 |
31 | """应用程序启动初始化
32 | """
33 |
34 | def __init__(self):
35 | routes = load('handler')
36 | settings = {
37 | 'static_path': os.path.join(os.path.dirname(__file__), "static"),
38 | 'template_path': os.path.join(os.path.dirname(__file__), "tpl"),
39 | 'xsrf_cookies': True,
40 | 'cookie_secret': 'tokyo',
41 | 'site_title': 'zkdash',
42 | 'ui_modules': uimodule,
43 | 'ui_methods': uimethods,
44 | 'debug': OPTIONS.debug,
45 | }
46 | tornado.web.Application.__init__(self, routes, **settings)
47 |
48 | def log_request(self, handler):
49 | """重写tornado request日志
50 | """
51 | status = handler.get_status()
52 | if status < 400:
53 | if handler.request.uri[0:7] == '/static':
54 | return
55 | log_method = log.info
56 | elif status < 500:
57 | log_method = log.warning
58 | else:
59 | log_method = log.error
60 | request_time = 1000.0 * handler.request.request_time()
61 | if request_time > 30 or OPTIONS.debug or status >= 400:
62 | log_method("%d %s %.2fms",
63 | status,
64 | handler._request_summary(),
65 | request_time)
66 |
67 |
68 | def make_clean():
69 | '''清理文件
70 | '''
71 | pyshell.shell("find . -name '*.pyc' | xargs rm -rf", debug=True)
72 |
73 |
74 | def main():
75 | """主程序入口
76 | """
77 | logger.init_logger(LOG_ITEMS, suffix=OPTIONS.port)
78 | application = Application()
79 | http_server = tornado.httpserver.HTTPServer(application,
80 | xheaders=True)
81 | http_server.listen(OPTIONS.port)
82 | tornado.ioloop.IOLoop.instance().start()
83 |
84 | if __name__ == "__main__":
85 | make_clean()
86 | main()
87 |
--------------------------------------------------------------------------------
/lib/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: Wanglichao
10 | 创建日期: 2014-12-06
11 | """
12 |
13 | from lib.utils.routes import Route as route
14 | from lib.utils.routes import load
15 |
--------------------------------------------------------------------------------
/lib/db/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLiChao
10 | 创建日期: 2014-12-06
11 | """
12 |
--------------------------------------------------------------------------------
/lib/db/database.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: database.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-26
11 | """
12 | # pylint: disable=invalid-name, bare-except
13 | from lib.db.retrydb import MyRetryDB
14 | from peewee import Model as _Model
15 | from peewee import DoesNotExist
16 | from peewee import OperationalError
17 |
18 |
19 | class Database(object):
20 |
21 | '''db封装,自动查找数据库
22 | '''
23 |
24 | def __init__(self, **connect_kwargs):
25 | self.connect_kwargs = connect_kwargs
26 | self.load_database()
27 | self.Model = self.get_model_class()
28 |
29 | def load_database(self):
30 | self.db = self.connect_kwargs.pop('db')
31 | self.database = MyRetryDB(self.db, **self.connect_kwargs)
32 | self.database.field_overrides.update({'enum': 'enum'}) # 增加枚举类型
33 |
34 | def get_model_class(self):
35 | '''获取基类model
36 | '''
37 | class BaseModel(_Model):
38 |
39 | '''BaseModel的封装
40 | '''
41 |
42 | class Meta(object):
43 | '''元类
44 | '''
45 | database = self.database
46 |
47 | @classmethod
48 | def one(cls, *query, **kwargs):
49 | '''获取单条数据
50 | Retruns:
51 | 返回单条数据不存在则返回None
52 | '''
53 | try:
54 | return cls.get(*query, **kwargs)
55 | except DoesNotExist:
56 | return None
57 |
58 | def delete_instance(self, *args, **kwargs):
59 | '''如果deleted字段存在自动使用逻辑删除
60 | '''
61 | if 'deleted' in self._meta.fields:
62 | setattr(self, 'deleted', '1')
63 | super(BaseModel, self).save()
64 | else:
65 | super(BaseModel, self).delete_instance(*args, **kwargs)
66 |
67 | def __hash__(self):
68 | """提供hash支持
69 | """
70 | return hash(self.id)
71 |
72 | return BaseModel
73 |
74 | def connect(self):
75 | '''主从建立连接,如果连接关闭重试
76 | '''
77 | i = 0
78 | while i < 4:
79 | try:
80 | if self.database.is_closed():
81 | self.database.get_conn().ping(True)
82 | break
83 | except OperationalError:
84 | self.close()
85 | i = i + 1
86 |
87 | def close(self):
88 | '''关闭连接
89 | '''
90 | try:
91 | self.database.close()
92 | except:
93 | pass
94 |
--------------------------------------------------------------------------------
/lib/db/retrydb.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 | """
3 | Copyright (c) 2014,掌阅科技
4 | All rights reserved.
5 |
6 | 摘 要: retrydb.py
7 | 创 建 者: zxb
8 | 创建日期: 2015-10-13
9 | """
10 | from peewee import MySQLDatabase
11 | from peewee import OperationalError
12 |
13 |
14 | class RetryDBMixin(object):
15 |
16 | __slots__ = ()
17 |
18 | def execute_sql(self, sql, params=None, require_commit=True):
19 | try:
20 | cursor = super(RetryDBMixin, self).execute_sql(
21 | sql, params, require_commit)
22 | except OperationalError:
23 | if not self.is_closed():
24 | # 手动关闭连接
25 | self.close()
26 | cursor = self.get_cursor()
27 | cursor.execute(sql, params or ())
28 | if require_commit and self.get_autocommit():
29 | self.commit()
30 | return cursor
31 |
32 |
33 | class MyRetryDB(RetryDBMixin, MySQLDatabase):
34 | pass
35 |
--------------------------------------------------------------------------------
/lib/excel/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2015,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-04-09
11 | '''
12 | from lib.excel.excel import ExcelWorkBook
13 |
--------------------------------------------------------------------------------
/lib/uimethods/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2015,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-10-10
11 | '''
12 |
13 | if __name__ == '__main__':
14 | pass
15 |
--------------------------------------------------------------------------------
/lib/uimodule/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-02-06
11 | """
12 | from lib.uimodule.paginate import Paginate
13 | from lib.uimodule.query import Query
14 |
--------------------------------------------------------------------------------
/lib/uimodule/paginate.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: paginate.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-02-06
11 | """
12 | # pylint: disable=arguments-differ
13 | from tornado.web import UIModule
14 |
15 |
16 | class Paginate(UIModule):
17 |
18 | '''分页组件
19 | '''
20 |
21 | def render(self, total, current_page, page_size):
22 | '''
23 | Args:
24 | total: 总数
25 | current_page: 当前页
26 | page_size: 页码数
27 | '''
28 | return self.render_string("uimodule/paginate.html",
29 | total=total,
30 | current_page=current_page,
31 | page_size=page_size)
32 |
--------------------------------------------------------------------------------
/lib/uimodule/query.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2015,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: query.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-03-06
11 | """
12 | # pylint: disable=arguments-differ
13 | from tornado.web import UIModule
14 |
15 | OPERATOR = {
16 | 'like': '包含',
17 | '=': '等于',
18 | '!=': '不等于',
19 | '>': '大于',
20 | '>=': '大于等于',
21 | '<': '小于',
22 | '<=': '小于等于',
23 | }
24 |
25 |
26 | class Query(UIModule):
27 |
28 | '''操作条件
29 | '''
30 |
31 | def render(self, column, default_column,
32 | default_operator, time_flag=False):
33 | '''
34 | Args:
35 | column: 数据库列字典
36 | default_column: 默认列
37 | operator: 操作字典
38 | default_operator: 默认操作
39 | time_flag: 输入为时间字段标记
40 | '''
41 | return self.render_string("uimodule/query.html",
42 | column=column,
43 | default_column=default_column,
44 | default_operator=default_operator,
45 | operator=OPERATOR,
46 | time_flag=time_flag)
47 |
--------------------------------------------------------------------------------
/lib/utils/logger.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2013,掌阅科技
6 | All rights reserved.
7 |
8 | File Name: logger.py
9 | Author: WangLichao
10 | Created on: 2014-03-28
11 | '''
12 | import os
13 | import os.path
14 | import logging
15 | import logging.handlers
16 | LOGGER_LEVEL = {
17 | 'DEBUG': logging.DEBUG,
18 | 'INFO': logging.INFO,
19 | 'WARNING': logging.WARNING,
20 | 'ERROR': logging.ERROR,
21 | 'CRITICAL': logging.CRITICAL
22 | }
23 |
24 |
25 | def init_logger(log_conf_items, suffix=None, log_name=None):
26 | """
27 | 初始化logger.
28 | Args:
29 | log_conf_items: 配置项list.
30 | """
31 | logger = logging.getLogger(log_name)
32 | for log_item in log_conf_items:
33 | path = os.path.expanduser(log_item['file'])
34 | if suffix:
35 | path = '%s.%s' % (path, suffix)
36 | dir_name = os.path.dirname(path)
37 | if dir_name and not os.path.exists(dir_name):
38 | os.makedirs(dir_name)
39 | handler = logging.handlers.TimedRotatingFileHandler(
40 | path,
41 | when=log_item['when'],
42 | interval=int(log_item['interval']),
43 | backupCount=int(log_item['backup_count']),
44 | )
45 | enable_levels = [LOGGER_LEVEL[i] for i in log_item['log_levels']]
46 | handler.addFilter(LevelFilter(enable_levels, False))
47 | handler.suffix = log_item['backup_suffix']
48 | formatter = logging.Formatter(log_item['format'])
49 | handler.setFormatter(formatter)
50 | logger.addHandler(handler)
51 | logger.setLevel(log_item['level'])
52 |
53 |
54 | class LevelFilter(logging.Filter):
55 |
56 | '''日志过滤器
57 | '''
58 |
59 | def __init__(self, passlevels, reject):
60 | super(LevelFilter, self).__init__()
61 | self.passlevels = passlevels
62 | self.reject = reject
63 |
64 | def filter(self, record):
65 | if self.reject:
66 | return record.levelno not in self.passlevels
67 | else:
68 | return record.levelno in self.passlevels
69 |
70 | if __name__ == '__main__':
71 | LOG_CONF = [{'name': 'operation', 'file': 'log/operation.log',
72 | 'level': 'DEBUG', 'format': '%(asctime)s %(levelname)s %(message)s'}]
73 | init_logger(LOG_CONF)
74 |
--------------------------------------------------------------------------------
/lib/utils/pyshell.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | '''
5 | Copyright (c) 2013,掌阅科技
6 | All rights reserved.
7 |
8 | File Name: pyshell.py
9 | Author: WangLichao
10 | Created on: 2014-03-21
11 | '''
12 | import subprocess
13 | import time
14 |
15 |
16 | def wait_process_end(process, timeout):
17 | '''等待进程终止
18 | Args:
19 | process: 进程句柄
20 | timeout: 超时时间
21 | Returns:
22 | 与shell的执行保持一致
23 | 0:成功
24 | 1:超时
25 | 2:错误
26 | '''
27 | if timeout <= 0:
28 | process.wait()
29 | return 0
30 | start_time = time.time()
31 | end_time = start_time + timeout
32 | while 1:
33 | ret = process.poll()
34 | if ret == 0:
35 | return 0
36 | elif ret is None:
37 | cur_time = time.time()
38 | if cur_time >= end_time:
39 | return 1
40 | time.sleep(0.1)
41 | else:
42 | return 2
43 |
44 |
45 | class ShellResult(object):
46 |
47 | '''封装shell执行的返回结果形式
48 | Attributes:
49 | return_code: 返回码
50 | stdout:标准输出
51 | stderr: 错误输出
52 | '''
53 |
54 | def __init__(self, return_code, stdout, stderr):
55 | self.return_code = return_code
56 | self.stdout = stdout
57 | self.stderr = stderr
58 |
59 |
60 | def shell(command, timeout=0, capture=False, debug=False):
61 | '''用于执行本地shell的功能
62 | Args:
63 | command: bash命令
64 | timeout: 命令的超时时间
65 | capture: 是否捕获输出结果
66 | debug: 是否输出debug信息
67 | Returns:
68 | 返回ShellResult对象
69 | '''
70 | if debug:
71 | print '=' * 35
72 | print '[local] ' + command
73 | print '=' * 35
74 | if capture:
75 | process = subprocess.Popen(command, stdin=subprocess.PIPE,
76 | stderr=subprocess.PIPE,
77 | stdout=subprocess.PIPE,
78 | shell=True)
79 | else:
80 | process = subprocess.Popen(command, shell=True)
81 | ret = wait_process_end(process, timeout)
82 | if ret == 1:
83 | process.terminate()
84 | raise Exception("terminated_for_timout")
85 | if capture:
86 | stdout = ''.join(process.stdout.readlines())
87 | stderr = ''.join(process.stderr.readlines())
88 | return ShellResult(process.returncode, stdout, stderr)
89 | else:
90 | return ShellResult(process.returncode, None, None)
91 |
--------------------------------------------------------------------------------
/lib/zyqconf/README.rst:
--------------------------------------------------------------------------------
1 | =======
2 | zyqconf
3 | =======
4 | 配置管理系统配套的python客户端
5 |
6 | 项目描述
7 | --------
8 | - QConf客户端python驱动包的进一步封装,与配置管理系统配套使用
9 | - 使用yaml对配置信息进行序列化,以便支持int和float类型
10 | - 支持python复杂数据结构,dict和list
11 | - 所有配置信息都是只可读,任何会改变配置信息的方法均不支持(dict和list的一些方法因此未提供支持)
12 |
13 | 项目依赖
14 | --------
15 | - QConf agent
16 | - yaml
17 |
18 | 版本变更
19 | --------
20 | - v0.0.1
21 | 提供基本功能
22 | - v1.0.0
23 | 增加钩子功能,方便在通过QConf获取配置失败时执行自定义函数
24 |
25 | 使用举例
26 | --------
27 |
28 | 获取配置管理系统的配置::
29 | import zyqconf
30 |
31 | # 字典节点需要存储特殊值 `DICT_ZNODE`
32 | dict_conf = zyqconf.DictNode('dict_node_path')
33 | print dict_conf.get('conf', '')
34 | print dict_conf.as_dict()
35 |
36 | # 列表节点需要存储特殊值 `LIST_ZNODE`
37 | list_conf = zyqconf.ListNode('list_node_path')
38 | print len(list_conf)
39 | print list_conf.as_list()
40 |
41 | 通过钩子注册获取配置失败时执行的回调函数::
42 | import zyqconf
43 |
44 | @zyqconf.hooks.on(zyqconf.HOOK_CONF_ERROR)
45 | def conf_error(path, exc_info):
46 | # do whatever you want
47 | print "conf error, path: {0}\n{1}".format(path, exc_info)
48 |
--------------------------------------------------------------------------------
/lib/zyqconf/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | '''
4 | Copyright (c) 2014,掌阅科技
5 | All rights reserved.
6 |
7 | 摘 要: __init__.py
8 | 创 建 者: zhuangshixiong
9 | 创建日期: 2015-09-09
10 | '''
11 | # pylint: disable=relative-import
12 | import qconf_py
13 | import hooks
14 | from .types import (
15 | QconfNode,
16 | ListNode,
17 | DictNode,
18 | HOOK_CONF_ERROR,
19 | )
20 |
21 | __version__ = '1.0.0'
22 |
23 | __all__ = [
24 | 'qconf_py',
25 | 'hooks',
26 | 'QconfNode',
27 | 'DictNode',
28 | 'ListNode',
29 | 'HOOK_CONF_ERROR',
30 | ]
31 |
--------------------------------------------------------------------------------
/lib/zyqconf/hooks.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | '''
4 | Copyright (c) 2014,掌阅科技
5 | All rights reserved.
6 |
7 | 摘 要: hooks.py
8 | 创 建 者: zhuangshixiong
9 | 创建日期: 2015-09-22
10 | '''
11 | # pylint: disable=invalid-name, missing-docstring
12 | from collections import defaultdict
13 |
14 |
15 | class Hook(object):
16 | """
17 | A single hook that can be listened for.
18 | """
19 | def __init__(self):
20 | self.subscribers = []
21 |
22 | def attach(self, task):
23 | """attach a task to this hook.
24 | """
25 | self.subscribers.append(task)
26 |
27 | def detach(self, task):
28 | """detach a task from this hook
29 | """
30 | self.subscribers.remove(task)
31 |
32 | def send(self, **kwargs):
33 | """send msg to tasks and return their results.
34 | """
35 | return [task(**kwargs) for task in self.subscribers]
36 |
37 |
38 | _HOOKS = defaultdict(Hook)
39 |
40 |
41 | def all_hooks():
42 | """
43 | Return all registered hooks.
44 | """
45 | return _HOOKS
46 |
47 |
48 | def get_hook(name):
49 | """
50 | Return hook with given name, creating it if necessary.
51 | """
52 | return _HOOKS[name]
53 |
54 |
55 | def on(name):
56 | """Return a decorator that attach the wrapped function to the hook with given name.
57 | """
58 | hook = get_hook(name)
59 |
60 | def hook_decorator(func):
61 | hook.attach(func)
62 | return func
63 | return hook_decorator
64 |
--------------------------------------------------------------------------------
/lib/zyqconf/qconf_py.so:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ireaderlab/zkdash/a9e27e9cc63dcfbb483a1fdfa00c98fd0b079739/lib/zyqconf/qconf_py.so
--------------------------------------------------------------------------------
/model/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/model/db/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/model/db/base.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: base.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-22
11 | """
12 | from peewee import Field
13 |
14 | from lib.db.database import Database
15 | from conf.settings import DATABASE
16 |
17 | # 后台管理数据库
18 | ZKDASH_DB = Database(**DATABASE)
19 |
20 |
21 | class EnumField(Field):
22 | """自定义枚举类型字段, peewee中不提供枚举类型
23 | """
24 | db_field = 'enum'
25 |
26 | def __init__(self, enum_value=None, *args, **kwargs):
27 | """枚举初始化
28 | """
29 | self.enum_value = enum_value
30 | super(EnumField, self).__init__(*args, **kwargs)
31 |
32 | def get_modifiers(self):
33 | """使用传递的枚举值
34 | """
35 | return self.enum_value and [self.enum_value] or None
36 |
--------------------------------------------------------------------------------
/model/db/zd_qconf_agent.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=invalid-name
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: zd_qconf_agent.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-08-26
11 | """
12 | from peewee import CharField
13 | from peewee import IntegerField
14 | from peewee import SQL
15 |
16 | from model.db.base import ZKDASH_DB, EnumField
17 |
18 |
19 | class ZdQconfAgent(ZKDASH_DB.Model):
20 |
21 | """ZdQconfAgent Model
22 | """
23 |
24 | id = IntegerField(primary_key=True, constraints=[SQL("AUTO_INCREMENT")])
25 | ip = CharField(max_length=32, null=True)
26 | hostname = CharField(max_length=32, null=True)
27 | cluster_name = CharField(max_length=32, null=True)
28 | notes = CharField(max_length=255, null=True)
29 | deleted = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")])
30 |
31 | class Meta(object):
32 |
33 | """表配置信息
34 | """
35 | db_table = "zd_qconf_agent"
36 |
--------------------------------------------------------------------------------
/model/db/zd_qconf_feedback.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=invalid-name
4 |
5 | """
6 | Copyright (c) 2014,掌阅科技
7 | All rights reserved.
8 |
9 | 摘 要: zd_qconf_feedback.py
10 | 创 建 者: zhuangshixiong
11 | 创建日期: 2015-06-24
12 | """
13 |
14 | from peewee import DateTimeField
15 | from peewee import CharField
16 | from peewee import IntegerField
17 | from peewee import SQL
18 |
19 | from model.db.base import ZKDASH_DB, EnumField
20 |
21 |
22 | class ZdQconfFeedback(ZKDASH_DB.Model):
23 |
24 | """ZdQconfFeedback Model
25 | """
26 |
27 | id = IntegerField(primary_key=True, constraints=[SQL("AUTO_INCREMENT")])
28 | hostname = CharField(max_length=32, null=True)
29 | ip = CharField(max_length=32, null=True)
30 | path = CharField(max_length=512, null=True)
31 | md5_value = CharField(max_length=128, null=True)
32 | idc = CharField(max_length=32, null=True)
33 | update_time = DateTimeField(null=True)
34 | data_type = CharField(null=True)
35 | execute_status = EnumField(enum_value="'0', '1', '2'", constraints=[SQL("DEFAULT '0'")])
36 | deleted = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")])
37 |
38 | class Meta(object):
39 |
40 | """表配置信息
41 | """
42 | db_table = "zd_qconf_feedback"
43 |
--------------------------------------------------------------------------------
/model/db/zd_snapshot.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=invalid-name
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: zd_snapshot.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-06-16
11 | """
12 | from peewee import DateTimeField
13 | from peewee import CharField
14 | from peewee import TextField
15 | from peewee import IntegerField
16 | from peewee import SQL
17 |
18 | from model.db.base import ZKDASH_DB, EnumField
19 |
20 |
21 | class ZdSnapshot(ZKDASH_DB.Model):
22 |
23 | """ZdSnapshot Model
24 | """
25 |
26 | id = IntegerField(primary_key=True, constraints=[SQL("AUTO_INCREMENT")])
27 | cluster_name = CharField(max_length=64, null=True)
28 | path = CharField(max_length=512, null=True)
29 | data = TextField(null=True)
30 | create_time = DateTimeField(null=True)
31 | commit = CharField(max_length=64, null=True)
32 | status = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")])
33 | deleted = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")])
34 |
35 | class Meta(object):
36 |
37 | """表配置信息
38 | """
39 | db_table = "zd_snapshot"
40 |
--------------------------------------------------------------------------------
/model/db/zd_snapshot_tree.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=invalid-name
4 |
5 | """
6 | Copyright (c) 2014,掌阅科技
7 | All rights reserved.
8 |
9 | 摘 要: zd_snapshot_tree.py
10 | 创 建 者: zhuangshixiong
11 | 创建日期: 2015-09-02
12 | """
13 |
14 | from peewee import CharField
15 | from peewee import IntegerField
16 | from peewee import SQL
17 |
18 | from model.db.base import ZKDASH_DB
19 |
20 |
21 | class ZdSnapshotTree(ZKDASH_DB.Model):
22 |
23 | """ZdSnapshotTree Model
24 | """
25 |
26 | id = IntegerField(primary_key=True, constraints=[SQL("AUTO_INCREMENT")])
27 | cluster_name = CharField(max_length=64, null=True)
28 | node_path = CharField(max_length=512, null=True)
29 | left = IntegerField(null=True)
30 | right = IntegerField(null=True)
31 |
32 | class Meta(object):
33 |
34 | """表配置信息
35 | """
36 | db_table = "zd_snapshot_tree"
37 |
--------------------------------------------------------------------------------
/model/db/zd_znode.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=invalid-name
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: zd_znode.py
9 | 创 建 者: zhuangshixiong
10 | 创建日期: 2015-06-16
11 | """
12 | from peewee import CharField
13 | from peewee import IntegerField
14 | from peewee import SQL
15 |
16 | from model.db.base import ZKDASH_DB, EnumField
17 |
18 |
19 | class ZdZnode(ZKDASH_DB.Model):
20 |
21 | """ZdZnode Model
22 | """
23 |
24 | id = IntegerField(primary_key=True, constraints=[SQL("AUTO_INCREMENT")])
25 | cluster_name = CharField(max_length=64, null=True)
26 | path = CharField(max_length=512, null=True)
27 | type = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")]) # 节点属于普通节点还是文件节点,默认普通节点
28 | business = CharField(max_length=64, null=True)
29 | deleted = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")])
30 |
31 | class Meta(object):
32 |
33 | """表配置信息
34 | """
35 | db_table = "zd_znode"
36 |
--------------------------------------------------------------------------------
/model/db/zd_zookeeper.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # pylint: disable=invalid-name
4 |
5 | """
6 | Copyright (c) 2014,掌阅科技
7 | All rights reserved.
8 |
9 | 摘 要: zd_zookeeper.py
10 | 创 建 者: zhuangshixiong
11 | 创建日期: 2015-06-23
12 | """
13 |
14 | from peewee import CharField
15 | from peewee import IntegerField
16 | from peewee import SQL
17 |
18 | from model.db.base import ZKDASH_DB, EnumField
19 |
20 |
21 | class ZdZookeeper(ZKDASH_DB.Model):
22 |
23 | """ZdZookeeper Model
24 | """
25 |
26 | id = IntegerField(primary_key=True, constraints=[SQL("AUTO_INCREMENT")])
27 | cluster_name = CharField(max_length=32)
28 | hosts = CharField(max_length=128)
29 | business = CharField(max_length=255)
30 | deleted = EnumField(enum_value="'0', '1'", constraints=[SQL("DEFAULT '0'")])
31 |
32 | class Meta(object):
33 |
34 | """表配置信息
35 | """
36 | db_table = "zd_zookeeper"
37 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | tornado==4.0
2 | peewee==2.4.7
3 | xlrd==0.9.3
4 | xlwt==0.7.5
5 | PyYAML==5.1
6 | pymysql==0.7.4
7 | argparse==1.2.1
8 | kazoo==2.1
9 |
--------------------------------------------------------------------------------
/service/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 |
4 | """
5 | Copyright (c) 2014,掌阅科技
6 | All rights reserved.
7 |
8 | 摘 要: __init__.py
9 | 创 建 者: WangLichao
10 | 创建日期: 2015-01-13
11 | """
12 |
13 |
14 | if __name__ == '__main__':
15 | pass
16 |
--------------------------------------------------------------------------------
/static/BJUI/js/minify.sh:
--------------------------------------------------------------------------------
1 | ###########################################
2 | # 摘 要: minify.sh
3 | # 创 建 者: WangLichao
4 | # 创建日期: 2015-06-02
5 | ###########################################
6 | #!/bin/bash
7 |
8 | rm bjui-all.js && touch bjui-all.js
9 | for js in `ls bjui-*.js|grep -v bjui-all.js|grep -v bjui-slidebar.js`;do
10 | echo $js "begin minify";
11 | java -jar yuicompressor-2.4.8.jar $js --charset utf-8 --type js >> bjui-all.js
12 | done
13 |
--------------------------------------------------------------------------------
/static/BJUI/js/yuicompressor-2.4.8.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ireaderlab/zkdash/a9e27e9cc63dcfbb483a1fdfa00c98fd0b079739/static/BJUI/js/yuicompressor-2.4.8.jar
--------------------------------------------------------------------------------
/static/BJUI/other/html5shiv.min.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed
3 | */
4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="