├── .gitignore ├── LICENSE ├── README.md ├── docs ├── K8S资源管控功能说明.md └── 灵活部署方案.md ├── install ├── 99.kubedoor-Mutating.yaml ├── grafana-ch-plugins │ ├── Dockerfile │ ├── build.sh │ └── plugins │ │ └── grafana-clickhouse-datasource │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── MANIFEST.txt │ │ ├── README.md │ │ ├── dashboards │ │ ├── cluster-analysis.json │ │ ├── data-analysis.json │ │ ├── opentelemetry-clickhouse.json │ │ ├── query-analysis.json │ │ └── system-dashboards.json │ │ ├── go_plugin_build_manifest │ │ ├── gpx_clickhouse_linux_amd64 │ │ ├── img │ │ └── logo.svg │ │ ├── module.js │ │ ├── module.js.map │ │ └── plugin.json ├── helm │ ├── kubedoor-1.3.2.tgz │ └── kubedoor │ │ ├── Chart.yaml │ │ ├── templates │ │ ├── 00.kubedoor │ │ │ ├── 01.clickhouse.yaml │ │ │ ├── 02.kubedoor-Dash.yaml │ │ │ ├── 031.kubedoor-master.yaml │ │ │ ├── 04.kubedoor-Web.yaml │ │ │ ├── 05.kubedoor-MCP.yaml │ │ │ └── 099.kubedoor-agent.yaml │ │ ├── 01.monit │ │ │ ├── 0.vm-single.yaml │ │ │ ├── 1.kube-state-metrics.yaml │ │ │ ├── 1.node-exporter.yaml │ │ │ ├── 1.vmagent.yaml │ │ │ ├── 2.vmalert.yaml │ │ │ ├── 3.alertmanager.yaml │ │ │ └── 4.kubedoor-alarm.yaml │ │ └── NOTES.txt │ │ ├── values-agent.yaml │ │ ├── values-master.yaml │ │ └── values.yaml ├── install-clickhouse.sh ├── kubedoor-init.sql ├── kubedoor-web.dockerfile ├── sslgen.sh ├── victoriametrics-docker-compose.yaml └── vmagent-job-config.yaml ├── screenshot ├── 1.0 │ ├── 1.png │ ├── 10.png │ ├── 11.jpg │ ├── 12.jpg │ ├── 13.jpg │ ├── 14.png │ ├── 15.jpg │ ├── 2.jpg │ ├── 3.png │ ├── 4.jpg │ ├── 5.png │ ├── 6.png │ ├── 7.jpg │ ├── 8.png │ ├── 9.png │ ├── kubedoor1.0-arch.png │ └── vm-arch.png ├── alert1.png ├── alert2.png ├── alert3.png ├── k8s-node.png ├── k8s-res.png ├── kd-k8s.png ├── kd-web.png ├── kd1.jpg ├── kd2.jpg ├── kd3.jpg └── kd4.jpg └── src ├── kubedoor-agent-go ├── Dockerfile ├── agent │ ├── agent.go │ ├── handleMessage.go │ └── requestCore.go ├── api │ ├── adminMutate.go │ ├── api.go │ ├── mutatingwebhook.go │ └── timeOpertor.go ├── asset │ └── asset.go ├── change.md ├── config │ ├── adminStruct.go │ ├── config.go │ └── variables.go ├── go.mod ├── go.sum ├── k8sSet │ └── k8sClient.go ├── main.go ├── pod-mgr.py ├── podmgr │ ├── autoJfr.go │ ├── autoJstack.go │ ├── autoJvmMem.go │ ├── autodump.go │ ├── podmgr.go │ └── public.go ├── requirements.txt ├── start.sh ├── tls.crt ├── tls.key ├── utils.py ├── utils │ └── utils.go └── version ├── kubedoor-agent ├── Dockerfile ├── __init__.py ├── debug-kubedoor-agent.py ├── kubedoor-agent.py ├── pod-mgr.py ├── requirements.txt ├── tls.crt ├── tls.key ├── utils.py └── version ├── kubedoor-alarm ├── Dockerfile ├── build.sh ├── kubedoor-alarm.py ├── requirements.txt └── utils.py ├── kubedoor-master ├── Dockerfile ├── __init__.py ├── kubedoor-master.py ├── prom_real_time_data.py ├── requirements.txt └── utils.py ├── kubedoor-mcp ├── Dockerfile ├── kubedoor-mcp.py └── requirements.txt └── kubedoor-web ├── .browserslistrc ├── .dockerignore ├── .editorconfig ├── .env.development ├── .env.production ├── .env.staging ├── .gitignore ├── .gitkeep ├── .husky ├── commit-msg ├── common.sh └── pre-commit ├── .lintstagedrc ├── .markdownlint.json ├── .npmrc ├── .nvmrc ├── .prettierrc.js ├── .stylelintignore ├── Dockerfile ├── LICENSE ├── README.md ├── build ├── cdn.ts ├── compress.ts ├── info.ts ├── optimize.ts ├── plugins.ts └── utils.ts ├── commitlint.config.js ├── config ├── eslint.config.js ├── index.html ├── locales ├── en.yaml └── zh-CN.yaml ├── mock ├── asyncRoutes.ts ├── login.ts └── refreshToken.ts ├── package.json ├── pnpm-lock.yaml ├── postcss.config.js ├── public ├── 18logo.png ├── 18logo1.png ├── favicon.ico ├── logo.svg └── platform-config.json ├── src ├── App.vue ├── api │ ├── alarm.ts │ ├── monit.ts │ ├── resource.ts │ ├── routes.ts │ ├── user.ts │ └── workbench.ts ├── assets │ ├── iconfont │ │ ├── iconfont.css │ │ ├── iconfont.js │ │ ├── iconfont.json │ │ ├── iconfont.ttf │ │ ├── iconfont.woff │ │ └── iconfont.woff2 │ ├── login │ │ ├── avatar.svg │ │ ├── bg.png │ │ └── illustration.svg │ ├── status │ │ ├── 403.svg │ │ ├── 404.svg │ │ └── 500.svg │ ├── svg │ │ ├── back_top.svg │ │ ├── dark.svg │ │ ├── day.svg │ │ ├── enter_outlined.svg │ │ ├── exit_screen.svg │ │ ├── full_screen.svg │ │ ├── globalization.svg │ │ ├── keyboard_esc.svg │ │ └── system.svg │ ├── table-bar │ │ ├── collapse.svg │ │ ├── drag.svg │ │ ├── expand.svg │ │ ├── refresh.svg │ │ └── settings.svg │ └── user.jpg ├── components │ ├── ReAuth │ │ ├── index.ts │ │ └── src │ │ │ └── auth.tsx │ ├── ReCol │ │ └── index.ts │ ├── ReDialog │ │ ├── index.ts │ │ ├── index.vue │ │ └── type.ts │ ├── ReIcon │ │ ├── index.ts │ │ └── src │ │ │ ├── hooks.ts │ │ │ ├── iconfont.ts │ │ │ ├── iconifyIconOffline.ts │ │ │ ├── iconifyIconOnline.ts │ │ │ ├── offlineIcon.ts │ │ │ └── types.ts │ ├── RePerms │ │ ├── index.ts │ │ └── src │ │ │ └── perms.tsx │ ├── RePureTableBar │ │ ├── index.ts │ │ └── src │ │ │ └── bar.tsx │ ├── ReSegmented │ │ ├── index.ts │ │ └── src │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ └── type.ts │ └── ReText │ │ ├── index.ts │ │ └── src │ │ └── index.vue ├── config │ └── index.ts ├── directives │ ├── auth │ │ └── index.ts │ ├── copy │ │ └── index.ts │ ├── index.ts │ ├── longpress │ │ └── index.ts │ ├── optimize │ │ └── index.ts │ ├── perms │ │ └── index.ts │ └── ripple │ │ ├── index.scss │ │ └── index.ts ├── layout │ ├── components │ │ ├── lay-content │ │ │ └── index.vue │ │ ├── lay-footer │ │ │ └── index.vue │ │ ├── lay-frame │ │ │ └── index.vue │ │ ├── lay-navbar │ │ │ └── index.vue │ │ ├── lay-notice │ │ │ ├── components │ │ │ │ ├── NoticeItem.vue │ │ │ │ └── NoticeList.vue │ │ │ ├── data.ts │ │ │ └── index.vue │ │ ├── lay-panel │ │ │ └── index.vue │ │ ├── lay-search │ │ │ ├── components │ │ │ │ ├── SearchFooter.vue │ │ │ │ ├── SearchHistory.vue │ │ │ │ ├── SearchHistoryItem.vue │ │ │ │ ├── SearchModal.vue │ │ │ │ └── SearchResult.vue │ │ │ ├── index.vue │ │ │ └── types.ts │ │ ├── lay-setting │ │ │ └── index.vue │ │ ├── lay-sidebar │ │ │ ├── NavHorizontal.vue │ │ │ ├── NavMix.vue │ │ │ ├── NavVertical.vue │ │ │ └── components │ │ │ │ ├── SidebarBreadCrumb.vue │ │ │ │ ├── SidebarCenterCollapse.vue │ │ │ │ ├── SidebarExtraIcon.vue │ │ │ │ ├── SidebarFullScreen.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ ├── SidebarLeftCollapse.vue │ │ │ │ ├── SidebarLinkItem.vue │ │ │ │ ├── SidebarLogo.vue │ │ │ │ └── SidebarTopCollapse.vue │ │ └── lay-tag │ │ │ ├── components │ │ │ └── TagChrome.vue │ │ │ ├── index.scss │ │ │ └── index.vue │ ├── frame.vue │ ├── hooks │ │ ├── useBoolean.ts │ │ ├── useDataThemeChange.ts │ │ ├── useLayout.ts │ │ ├── useMultiFrame.ts │ │ ├── useNav.ts │ │ ├── useTag.ts │ │ └── useTranslationLang.ts │ ├── index.vue │ ├── redirect.vue │ ├── theme │ │ └── index.ts │ └── types.ts ├── main.ts ├── plugins │ ├── echarts.ts │ ├── elementPlus.ts │ └── i18n.ts ├── router │ ├── index.ts │ ├── modules │ │ ├── alarm.ts │ │ ├── collection.ts │ │ ├── error.ts │ │ ├── monit.ts │ │ ├── monitk8s.ts │ │ ├── monitnode.ts │ │ ├── peakhours.ts │ │ ├── remaining.ts │ │ ├── resource.ts │ │ ├── statistics.ts │ │ └── workbench.ts │ └── utils.ts ├── store │ ├── index.ts │ ├── modules │ │ ├── app.ts │ │ ├── epTheme.ts │ │ ├── multiTags.ts │ │ ├── permission.ts │ │ ├── search.ts │ │ ├── settings.ts │ │ └── user.ts │ ├── types.ts │ └── utils.ts ├── style │ ├── dark.scss │ ├── element-plus.scss │ ├── index.scss │ ├── login.css │ ├── reset.scss │ ├── sidebar.scss │ ├── tailwind.css │ └── transition.scss ├── utils │ ├── auth.ts │ ├── globalPolyfills.ts │ ├── http │ │ ├── index.ts │ │ └── types.d.ts │ ├── localforage │ │ ├── index.ts │ │ └── types.d.ts │ ├── message.ts │ ├── mitt.ts │ ├── preventDefault.ts │ ├── print.ts │ ├── progress │ │ └── index.ts │ ├── propTypes.ts │ ├── responsive.ts │ ├── sso.ts │ └── tree.ts └── views │ ├── alarm │ ├── detail.vue │ └── index.vue │ ├── collection │ ├── index.vue │ └── utils │ │ └── hook.tsx │ ├── error │ ├── 403.vue │ ├── 404.vue │ └── 500.vue │ ├── login │ ├── index.vue │ └── utils │ │ ├── motion.ts │ │ ├── rule.ts │ │ └── static.ts │ ├── monit │ ├── index.vue │ ├── scale │ │ └── index.vue │ └── utils │ │ └── hook.tsx │ ├── monitk8s │ └── index.vue │ ├── monitnode │ └── index.vue │ ├── permission │ ├── button │ │ ├── index.vue │ │ └── perms.vue │ └── page │ │ └── index.vue │ ├── resource │ ├── form │ │ └── index.vue │ ├── headerOperator.vue │ ├── index.vue │ ├── scale │ │ └── index.vue │ └── utils │ │ ├── hook.tsx │ │ ├── rule.ts │ │ └── types.ts │ ├── statistics │ └── index.vue │ └── workbench │ ├── index.vue │ └── index1.vue ├── stylelint.config.js ├── tailwind.config.ts ├── tsconfig.json ├── types ├── directives.d.ts ├── global-components.d.ts ├── global.d.ts ├── index.d.ts ├── router.d.ts ├── shims-tsx.d.ts └── shims-vue.d.ts ├── vite.config.ts └── 花折 /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2025 CassTime 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /docs/K8S资源管控功能说明.md: -------------------------------------------------------------------------------- 1 | ### 🛡基于K8S Mutating Webhook针对微服务Pod数、需求值、限制值强管控的准入控制能力 2 | 3 | #### 🚧当微服务更新部署时,基于K8S准入控制机制对资源进行管控【默认不开启】: 4 | - 🧮**控制每个微服务的Pod数、需求值、限制值**必须与数据库(数据来源为:**最近10天最大资源使用日的高峰时段各资源P95数值**)一致,以确保微服务的真实使用率和资源申请需求值相等,从而实现微服务的统一管控与Pod的负载感知调度均衡能力。 5 | - 🚫**对未管控的微服务,会部署失败并通知**,必须在WEB UI新增微服务后才能部署。(作为新增微服务的唯一管控入口,杜绝未经允许的新服务部署。) 6 | - 🌟通过本项目基于**K8S准入机制的扩展**思路,大家可以自行简单定制需求,即可对K8S实现各种高灵活性与扩展性附加能力,诸如统一或者个性化的**拦截、管理、策略、标记微服务**等功能。 7 | 8 |
9 | 10 | **K8S准入控制逻辑** 11 | 12 | ![kd-k8s](https://raw.githubusercontent.com/CassInfra/KubeDoor/refs/heads/main/screenshot/kd-k8s.png) 13 | 14 |
15 | 16 | ## ⛔注意事项 17 | 18 | - 部署完成后,**默认不会开启管控机制**,您可以在`WebUI`-`Agent管理`页面来开启`准入控制`以及设置需要`管控的命名空间`。特殊情况下,您也可以在相应的K8S使用`kubectl`来开关管控功能: 19 | 20 | ```bash 21 | # 开启管控 22 | kubectl apply -f https://StarsL.cn/kubedoor/99.kubedoor-Mutating.yaml 23 | 24 | # 关闭管控 25 | kubectl delete mutatingwebhookconfigurations kubedoor-admis-configuration 26 | ``` 27 | 28 | - **开启管控机制后**,目前只会拦截**deployment的创建,更新,扩缩容**操作;管控**pod数,需求值,限制值**。不会控制其它操作和属性。 29 | 30 | - **开启管控机制后**,通过任何方式对Deployment执行扩缩容或者更新操作都会受到管控。 31 | 32 | - **开启管控机制后**,扩缩容或者重启Deployment时,Pod数优先取`指定Pod`字段,若该字段为-1,则取`当日Pod`字段。 33 | 34 | ## 🌰管控例子 35 | 36 | - 您通过Kubectl对一个Deployment执行了扩容10个Pod后,**会触发拦截机制**,到数据库中去查询该微服务的Pod,然后使用该值来进行实际的扩缩容。(正确的做法应该是在KubeDoor-Web来执行扩缩容操作。) 37 | 38 | - 您通过某发布系统修改了Deployment的镜像版本,执行发布操作,**会触发拦截机制**,到数据库中去查询该微服务的Pod数,需求值,限制值,然后使用这些值值以及新的镜像来进行实际的更新操作。 39 | 40 | ## 🚩管控原则 41 | 42 | - **您对deployment的操作不会触发deployment重启的,也没有修改Pod数的:** 触发管控拦截后,只会按照您的操作来更新deployment(不会重启Deployment) 43 | 44 | - **您对deployment的操作不会触发deployment重启的,并且修改Pod数的:** 触发管控拦截后,Pod数会根据数据库的值以及您修改的其它信息来更新Deployment。(不会重启Deployment) 45 | 46 | - **您对deployment的操作会触发deployment重启的:** 触发管控拦截后,会到数据库中去查询该微服务的Pod数,需求值,限制值,然后使用这些值以及您修改的其它信息来更新Deployment。(会重启Deployment) 47 | 48 | --- 49 | 50 | -------------------------------------------------------------------------------- /install/grafana-ch-plugins/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/busybox:1.37.0 2 | RUN mkdir -p /app/plugins 3 | COPY plugins /app/plugins 4 | WORKDIR /app 5 | CMD ["sh", "-c", "cp -r ./plugins/ /var/lib/grafana/plugins/"] 6 | -------------------------------------------------------------------------------- /install/grafana-ch-plugins/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | docker build -t grafana-plugins-init:0.1.0 . 3 | docker login --username=starsliao@163.com registry.cn-shenzhen.aliyuncs.com 4 | docker tag grafana-plugins-init:0.1.0 registry.cn-shenzhen.aliyuncs.com/starsl/grafana-plugins-init:0.1.0 5 | docker push registry.cn-shenzhen.aliyuncs.com/starsl/grafana-plugins-init:0.1.0 -------------------------------------------------------------------------------- /install/grafana-ch-plugins/plugins/grafana-clickhouse-datasource/MANIFEST.txt: -------------------------------------------------------------------------------- 1 | 2 | -----BEGIN PGP SIGNED MESSAGE----- 3 | Hash: SHA512 4 | 5 | { 6 | "manifestVersion": "2.0.0", 7 | "signatureType": "grafana", 8 | "signedByOrg": "grafana", 9 | "signedByOrgName": "Grafana Labs", 10 | "plugin": "grafana-clickhouse-datasource", 11 | "version": "4.5.1", 12 | "time": 1732723439276, 13 | "keyId": "7e4d0c6a708866e7", 14 | "files": { 15 | "CHANGELOG.md": "b26eac2592fcfc6b49017c6b7aa646cbeb6fd294d9858ab815cdc5899db63709", 16 | "LICENSE": "cdd15e614b50e88443fe574ad56bde5ba697d958a45376431638eea816e3bfc3", 17 | "README.md": "01c2a56425fa4fb836dcb30b7575b0ed031be483567704025e160497e5002e24", 18 | "dashboards/cluster-analysis.json": "7f83d4d09cc6f045768f5bf47485b864dd6da03094f8607808dec77cb96902e5", 19 | "dashboards/data-analysis.json": "71695f08dfad47f3d4da4c2d331a09eb8fe5789520d5566fffeecd626079caa1", 20 | "dashboards/opentelemetry-clickhouse.json": "7000bb0d91bf0474eb5da966ee65fece8a591785e4a06f8dc7c4431fef35314a", 21 | "dashboards/query-analysis.json": "1b2006a3f4142e512e50156a7d2fd8cf03a178019aaccc964c0283c8559298b3", 22 | "dashboards/system-dashboards.json": "a47eb47b9cd0bea82a7276fc805bba214164e677f68fb1e821b0278b17bee7f0", 23 | "go_plugin_build_manifest": "7980a82c9b5646c237a4e240e3879ba6a836566b6dbe746cb68c907921188732", 24 | "gpx_clickhouse_linux_amd64": "e82417afbb902d68d92b5642b960bf73fc1dd704ada857ac8cbbcca750cc9325", 25 | "img/logo.svg": "838199055d86584ff105e5e91013203a6acb7d3f2061ae27678786125ab11f09", 26 | "module.js": "43d526f5ce85220d933be0e13f0c5366a94803ed5cef1f7e063cedf38e3ee928", 27 | "module.js.map": "ad3f2563a5046771e4d4612df16510626a4409f190bd8ed9e298949d73f0e4a5", 28 | "plugin.json": "b4524075328deadf099e0495ae01d3ae5b760476ec03c3f8e5d41f5c9b2fcedd" 29 | } 30 | } 31 | -----BEGIN PGP SIGNATURE----- 32 | Version: OpenPGP.js v4.10.11 33 | Comment: https://openpgpjs.org 34 | 35 | wrkEARMKAAYFAmdHQu8AIQkQfk0ManCIZucWIQTzOyW2kQdOhGNlcPN+TQxq 36 | cIhm52zYAgkAWJJXhB8b+hluiXDS8TbWSpezuWsHmfzKsiIkHozIuf6Tp2By 37 | WpcvqaSpjFwRo3epjSC2n0U9oDsgjGr8byQgTJoCCQHKnKU6hwj1Fd8i+Eeu 38 | n5eqC1PgnWfgKnc3lABkt8ei3DokjtpsIwChPST90c8AoN/VHo/mWqAvASNc 39 | 2Es6MKjmJQ== 40 | =fEpz 41 | -----END PGP SIGNATURE----- 42 | -------------------------------------------------------------------------------- /install/grafana-ch-plugins/plugins/grafana-clickhouse-datasource/go_plugin_build_manifest: -------------------------------------------------------------------------------- 1 | 04707ad0a7f03cb6ab28466b82d791e7578c8d11274c4855d226acf11d5ecafb:Magefile.go 2 | 633cead7326f37a33d950c6ed57bbc517125664069b6bd7679b56c524218f0a2:pkg/converters/converters.go 3 | a1c6a6171521d93dfc24353416a2bf90f3db3f51301888a18c98f950189f3e67:pkg/converters/converters_test.go 4 | 847ff0c9fc6ff85d85c3997e1f48fbf922cae7143c56f2f6b8a42559f2919b5b:pkg/macros/macros.go 5 | 3a39042ce625ec33b2003a162d57d5a86a21ae6445e66ffc33d518ac88fe0b51:pkg/macros/macros_test.go 6 | 67ffdde8c54a45348f13695d4c8312f990549fd375665f3506361f14fb68c468:pkg/main.go 7 | ce3bd56371c3918a2f81e9f1fbb7357e3d8b9babc1691897e1912630852f263f:pkg/plugin/datasource.go 8 | 465f9c7963d197f6f864fe107c33beef49d50cd41720c093a55805e19402d4a6:pkg/plugin/driver.go 9 | 4e91d18deaf83fd5bc3617a185aa2fdecabb5b5427ff47fbd69098ebc24cdbe8:pkg/plugin/driver_test.go 10 | 51ee8486dde6fea63e682154446cf3b47376d63b0d60eaadeb5823f792a07ce7:pkg/plugin/errors.go 11 | d0d5ece8062b1d1debeacae64fd68b69fbc9add3dd975f5f84db8ebfa0134613:pkg/plugin/settings.go 12 | 699e8c9e73b4293d9b80be7013f336c855400c7b795cfb2d9f6c4c0804427b78:pkg/plugin/settings_test.go 13 | -------------------------------------------------------------------------------- /install/grafana-ch-plugins/plugins/grafana-clickhouse-datasource/gpx_clickhouse_linux_amd64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/install/grafana-ch-plugins/plugins/grafana-clickhouse-datasource/gpx_clickhouse_linux_amd64 -------------------------------------------------------------------------------- /install/grafana-ch-plugins/plugins/grafana-clickhouse-datasource/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /install/grafana-ch-plugins/plugins/grafana-clickhouse-datasource/plugin.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://raw.githubusercontent.com/grafana/grafana/main/docs/sources/developers/plugins/plugin.schema.json", 3 | "alerting": true, 4 | "annotations": true, 5 | "backend": true, 6 | "category": "sql", 7 | "dependencies": { 8 | "grafanaDependency": "\u003e=9.5.0", 9 | "plugins": [] 10 | }, 11 | "executable": "gpx_clickhouse", 12 | "id": "grafana-clickhouse-datasource", 13 | "includes": [ 14 | { 15 | "name": "Query Analysis", 16 | "path": "dashboards/query-analysis.json", 17 | "type": "dashboard" 18 | }, 19 | { 20 | "name": "Data Analysis", 21 | "path": "dashboards/data-analysis.json", 22 | "type": "dashboard" 23 | }, 24 | { 25 | "name": "Cluster Analysis", 26 | "path": "dashboards/cluster-analysis.json", 27 | "type": "dashboard" 28 | }, 29 | { 30 | "name": "ClickHouse OTel Dashboard", 31 | "path": "dashboards/opentelemetry-clickhouse.json", 32 | "type": "dashboard" 33 | }, 34 | { 35 | "name": "ClickHouse System Dashboards", 36 | "path": "dashboards/system-dashboards.json", 37 | "type": "dashboard" 38 | } 39 | ], 40 | "info": { 41 | "author": { 42 | "name": "Grafana Labs" 43 | }, 44 | "build": { 45 | "time": 1732723429280, 46 | "repo": "https://github.com/grafana/clickhouse-datasource", 47 | "branch": "main", 48 | "hash": "1d56c57c04de91749cff198f86292e04c4e1138d", 49 | "build": 2565 50 | }, 51 | "description": "ClickHouse datasource plugin for Grafana", 52 | "keywords": [ 53 | "Simple" 54 | ], 55 | "links": [ 56 | { 57 | "name": "Website", 58 | "url": "https://github.com/grafana/clickhouse-datasource" 59 | }, 60 | { 61 | "name": "License", 62 | "url": "https://github.com/grafana/clickhouse-datasource/blob/master/LICENSE" 63 | } 64 | ], 65 | "logos": { 66 | "large": "img/logo.svg", 67 | "small": "img/logo.svg" 68 | }, 69 | "screenshots": [], 70 | "updated": "2024-11-27", 71 | "version": "4.5.1" 72 | }, 73 | "logs": true, 74 | "metrics": true, 75 | "name": "ClickHouse", 76 | "tracing": true, 77 | "type": "datasource" 78 | } -------------------------------------------------------------------------------- /install/helm/kubedoor-1.3.2.tgz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/install/helm/kubedoor-1.3.2.tgz -------------------------------------------------------------------------------- /install/helm/kubedoor/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: kubedoor 3 | type: application 4 | description: "花折 - KubeDoor" 5 | sources: 6 | - https://github.com/starsliao/KubeDoor 7 | maintainers: 8 | - name: StarsL.cn 9 | - url: https://github.com/starsliao 10 | 11 | version: 1.3.0 12 | appVersion: "1.3.0" 13 | -------------------------------------------------------------------------------- /install/helm/kubedoor/templates/00.kubedoor/05.kubedoor-MCP.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kubedoor.master.enable }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: kubedoor-mcp 6 | namespace: kubedoor 7 | labels: 8 | app: kubedoor-mcp 9 | spec: 10 | replicas: 1 11 | selector: 12 | matchLabels: 13 | app: kubedoor-mcp 14 | template: 15 | metadata: 16 | labels: 17 | app: kubedoor-mcp 18 | spec: 19 | containers: 20 | - name: kubedoor-mcp 21 | image: {{ .Values.image.repository }}/kubedoor-mcp:{{ .Values.image.kubedoor_mcp_tag }} 22 | env: 23 | - name: TZ 24 | value: Asia/Shanghai 25 | resources: 26 | limits: 27 | cpu: "1" 28 | memory: 1Gi 29 | requests: 30 | cpu: 1m 31 | memory: 1Mi 32 | livenessProbe: 33 | tcpSocket: 34 | port: 8000 35 | timeoutSeconds: 1 36 | periodSeconds: 10 37 | successThreshold: 1 38 | failureThreshold: 3 39 | readinessProbe: 40 | tcpSocket: 41 | port: 8000 42 | timeoutSeconds: 1 43 | periodSeconds: 10 44 | successThreshold: 1 45 | failureThreshold: 3 46 | imagePullPolicy: Always 47 | restartPolicy: Always 48 | --- 49 | apiVersion: v1 50 | kind: Service 51 | metadata: 52 | name: kubedoor-mcp 53 | namespace: kubedoor 54 | labels: 55 | app: kubedoor-mcp 56 | spec: 57 | ports: 58 | - name: http 59 | protocol: TCP 60 | port: 8000 61 | targetPort: 8000 62 | selector: 63 | app: kubedoor-mcp 64 | type: NodePort 65 | externalTrafficPolicy: Cluster 66 | {{- end }} 67 | -------------------------------------------------------------------------------- /install/helm/kubedoor/templates/01.monit/0.vm-single.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kubedoor.master.enable }} 2 | {{- if eq .Values.tsdb.type "KubeDoor" }} 3 | apiVersion: apps/v1 4 | kind: Deployment 5 | metadata: 6 | name: victoria-metrics 7 | namespace: kubedoor 8 | spec: 9 | selector: 10 | matchLabels: 11 | app: victoria-metrics 12 | template: 13 | metadata: 14 | labels: 15 | app: victoria-metrics 16 | spec: 17 | volumes: 18 | - name: storage 19 | persistentVolumeClaim: 20 | claimName: kubedoor-victoriametrics-data 21 | containers: 22 | - name: vm 23 | image: registry.cn-shenzhen.aliyuncs.com/starsl/victoria-metrics:stable 24 | imagePullPolicy: IfNotPresent 25 | args: 26 | - -storageDataPath=/var/lib/victoria-metrics-data 27 | - -retentionPeriod={{ .Values.tsdb.vm_single.retention }} 28 | - -httpAuth.username={{ .Values.tsdb.vm_single.user }} 29 | - -httpAuth.password={{ .Values.tsdb.vm_single.passwd }} 30 | - -search.maxQueryLen=655350 31 | ports: 32 | - containerPort: 8428 33 | name: http 34 | volumeMounts: 35 | - mountPath: /var/lib/victoria-metrics-data 36 | name: storage 37 | env: 38 | - name: TZ 39 | value: Asia/Shanghai 40 | resources: 41 | limits: 42 | cpu: '4' 43 | memory: 8Gi 44 | requests: 45 | cpu: 150m 46 | memory: 512Mi 47 | strategy: 48 | type: RollingUpdate 49 | rollingUpdate: 50 | maxUnavailable: 1 51 | maxSurge: 1 52 | --- 53 | apiVersion: v1 54 | kind: Service 55 | metadata: 56 | name: victoria-metrics 57 | namespace: kubedoor 58 | spec: 59 | ports: 60 | - port: 8428 61 | type: NodePort 62 | selector: 63 | app: victoria-metrics 64 | --- 65 | apiVersion: v1 66 | kind: PersistentVolumeClaim 67 | metadata: 68 | name: kubedoor-victoriametrics-data 69 | namespace: kubedoor 70 | spec: 71 | accessModes: 72 | - ReadWriteOnce 73 | resources: 74 | requests: 75 | storage: {{ .Values.tsdb.vm_single.storage }} 76 | storageClassName: {{ .Values.storageClass }} 77 | {{- end }} 78 | {{- end }} 79 | -------------------------------------------------------------------------------- /install/helm/kubedoor/templates/01.monit/1.node-exporter.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.monit.node_exporter.enable }} 2 | apiVersion: apps/v1 3 | kind: DaemonSet 4 | metadata: 5 | name: node-exporter 6 | namespace: kubedoor 7 | labels: 8 | app: node-exporter 9 | spec: 10 | selector: 11 | matchLabels: 12 | app: node-exporter 13 | template: 14 | metadata: 15 | labels: 16 | app: node-exporter 17 | spec: 18 | hostPID: true 19 | hostIPC: true 20 | hostNetwork: true 21 | containers: 22 | - name: node-exporter 23 | image: registry.cn-shenzhen.aliyuncs.com/starsl/node-exporter 24 | ports: 25 | - containerPort: 9100 26 | resources: 27 | requests: 28 | cpu: 50m 29 | memory: 20Mi 30 | limits: 31 | cpu: 500m 32 | memory: 400Mi 33 | securityContext: 34 | privileged: true 35 | args: 36 | - --path.procfs=/host/proc 37 | - --path.sysfs=/host/sys 38 | - --path.rootfs=/host/root 39 | - --no-collector.wifi 40 | - --no-collector.hwmon 41 | # - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys|var/lib/docker/.+)($|/) 42 | - --collector.filesystem.ignored-mount-points=^/(dev|proc|sys)($|/) 43 | - --collector.filesystem.ignored-fs-types=^(tmpfs|autofs|binfmt_misc|cgroup|configfs|debugfs|devpts|devtmpfs|fusectl|hugetlbfs|mqueue|overlay|proc|procfs|pstore|rpc_pipefs|securityfs|sysfs|tracefs)$ 44 | volumeMounts: 45 | - mountPath: /host/proc 46 | name: proc 47 | readOnly: false 48 | - mountPath: /host/sys 49 | name: sys 50 | readOnly: false 51 | - mountPath: /host/root 52 | mountPropagation: HostToContainer 53 | name: root 54 | readOnly: true 55 | 56 | securityContext: 57 | runAsUser: 0 58 | tolerations: 59 | - operator: Exists 60 | volumes: 61 | - hostPath: 62 | path: /proc 63 | name: proc 64 | - hostPath: 65 | path: /sys 66 | name: sys 67 | - hostPath: 68 | path: / 69 | name: root 70 | {{- end }} 71 | -------------------------------------------------------------------------------- /install/helm/kubedoor/templates/01.monit/4.kubedoor-alarm.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.kubedoor.master.enable }} 2 | apiVersion: apps/v1 3 | kind: Deployment 4 | metadata: 5 | name: kubedoor-alarm 6 | namespace: kubedoor 7 | labels: 8 | app: kubedoor-alarm 9 | app.kubernetes.io/instance: kubedoor-alarm 10 | spec: 11 | replicas: 1 12 | selector: 13 | matchLabels: 14 | app: kubedoor-alarm 15 | template: 16 | metadata: 17 | labels: 18 | app: kubedoor-alarm 19 | spec: 20 | containers: 21 | - name: kubedoor-alarm 22 | image: {{ .Values.image.repository }}/kubedoor-alarm:{{ .Values.image.kubedoor_alarm_tag }} 23 | envFrom: 24 | - configMapRef: 25 | name: kubedoor-config 26 | env: 27 | - name: TZ 28 | value: Asia/Shanghai 29 | resources: 30 | limits: 31 | cpu: '1' 32 | memory: 1Gi 33 | requests: 34 | cpu: 10m 35 | memory: 10Mi 36 | livenessProbe: 37 | tcpSocket: 38 | port: 80 39 | timeoutSeconds: 1 40 | periodSeconds: 10 41 | successThreshold: 1 42 | failureThreshold: 3 43 | readinessProbe: 44 | tcpSocket: 45 | port: 80 46 | timeoutSeconds: 1 47 | periodSeconds: 10 48 | successThreshold: 1 49 | failureThreshold: 3 50 | imagePullPolicy: Always 51 | restartPolicy: Always 52 | --- 53 | apiVersion: v1 54 | kind: Service 55 | metadata: 56 | name: kubedoor-alarm 57 | namespace: kubedoor 58 | labels: 59 | app: kubedoor-alarm 60 | app.kubernetes.io/instance: kubedoor-alarm 61 | 62 | spec: 63 | ports: 64 | - name: http 65 | protocol: TCP 66 | port: 80 67 | selector: 68 | app: kubedoor-alarm 69 | {{- end }} 70 | -------------------------------------------------------------------------------- /install/helm/kubedoor/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | {{- if .Values.kubedoor.master.enable }} 2 | 🎉 3 | # ClickHouse 4 | ClickHouse WEBUI: http://{{ .Values.clickhouse.CK_HOST }}:{{ .Values.clickhouse.CK_HTTP_PORT }}/play 5 | ClickHouse 用户名: {{ .Values.clickhouse.CK_USER }} 6 | ClickHouse 密码: {{ .Values.clickhouse.CK_PASSWORD }} 7 | 8 | # TSDB 9 | {{- if eq .Values.tsdb.type "KubeDoor" }} 10 | 时序数据库类型: KubeDoor (Victoria-Metrics-Single) 11 | Victoria-Metrics WEBUI: http://{{ .Values.tsdb.vm_single.user }}:{{ .Values.tsdb.vm_single.passwd }}@victoria-metrics.kubedoor:8428 12 | vmagent配置远程写地址: http://{{ .Values.tsdb.vm_single.user }}:{{ .Values.tsdb.vm_single.passwd }}@victoria-metrics.kubedoor:8428/api/v1/write 13 | 注意: 跨K8S访问时,请把victoria-metrics.kubedoor:8428替换为您外部可访问的IP和端口 14 | {{- else if eq .Values.tsdb.type "Victoria-Metrics-Cluster" }} 15 | 时序数据库类型: Victoria-Metrics-Cluster 16 | Victoria-Metrics远程读地址: {{ .Values.tsdb.remoteRead }} 17 | vmagent配置远程写地址: {{ .Values.tsdb.remoteWrite }} 18 | {{- else }} 19 | 时序数据库类型: Victoria-Metrics-Single 20 | Victoria-Metrics WEBUI: {{ .Values.tsdb.url }} 21 | vmagent配置远程写地址: {{ .Values.tsdb.url }}/api/v1/write 22 | {{- end }} 23 | 24 | 统一的external_labels_key: {{ .Values.tsdb.external_labels_key }} 25 | 26 | # KubeDoor web 27 | KubeDoor webUI: http://{nodeIP}:{kubedoor-web-NodePort} 28 | 默认账号密码都是: kubedoor 29 | 30 | # KubeDoor MCP URL 31 | http://{nodeIP}:{kubedoor-mcp-NodePort}/sse 32 | {{- else }} 33 | 🎉 34 | KubeDoor Agent: {{ .Values.tsdb.external_labels_value }} 安装完成。 35 | 请访问KubeDoor-Web,点击agent管理,找到您部署的agent:{{ .Values.tsdb.external_labels_value }},状态应该是在线,先开启自动采集,设置好高峰期时段,再执行采集:输入需要采集的历史数据时长,点击采集,即可采集历史数据并更新高峰时段数据到管控表。 36 | 37 | 注意:如果您是新安装的监控系统,并且已过了当天的高峰期时段,将会无法采集到数据;需要等第二天高峰期时段之后才能采集到数据。或者临时修改高峰时段为采集过监控数据的时段,再手动点击采集。 38 | {{- end }} 39 | -------------------------------------------------------------------------------- /install/helm/kubedoor/values-agent.yaml: -------------------------------------------------------------------------------- 1 | # 这是kubedoor-agent端的配置,kubedoor-agent需要连接master端的kubedoor-web,Prometheus/vmagent需要远程写时序数据库 2 | 3 | kubedoor: 4 | agent: 5 | enable: true 6 | master: 7 | ws: "ws://kubedoor-master.kubedoor" # master和agent在同一个K8S,可以直接配置kubedoor-master的service,免认证。 8 | #ws: "ws://Up4biLko1dNh:qCa22jDkfc9y@kubedoor-web外部IP:端口" # 跨K8S访问请使用kubedoor-web外部可访问的地址和端口,并配置认证信息。 9 | 10 | config: 11 | # 这里填写通知的信息,大部分操作会通过该机器人进行通知,钉钉机器人安全设置的自定义关键词请设置为:告警 12 | MSG_TYPE: "wecom" # 各类操作通知的消息类型:wecom, dingding, feishu 13 | MSG_TOKEN: "2cewgb-xxx-xxx-65209d" # 通知服务对应的token 14 | 15 | #java服务执行dump、jfr、jstack时会把数据存放到OBS,请填写您的OBS地址。(暂无OBS可以安装后在agent端修改,注意设置允许内网免认证上传。) 16 | OSS_URL: "https://xxxxxxxxx.obs.cn-south-1.myhuaweicloud.com" 17 | 18 | 19 | tsdb: 20 | # 以下两个字段用于多K8S监控数据,通过远程写方式,写入到同一个时序数据库的场景,即为Prometheus/vmagent设置中的external_labels的key/value。 21 | # 使用远程存储时,这个key/value会作为标签增加到每一个指标中,这样通过这个标签就可以区分出指标属于哪个K8S了。 22 | 23 | external_labels_key: "origin_prometheus" # 注意key只能字母数字下划线。注意所有external_labels_key的值都相同。 24 | # 请填写您的K8S名称。如果是使用您已有的Prometheus,请在您的Prometheus配置中找到external_labels的value填入。 25 | external_labels_value: "my-test-k8s" 26 | 27 | 28 | #【注意】如果您当前K8S已经有完整的Prometheus/vmagent监控,并且是远程写入时序数据库,则以下remoteWriteUrl不用管,并且请把以下所有的enable都设置为false,将不会安装false的组件。 29 | 30 | # 这是vmagent远程写Victoria-Metrics的地址。如果您使用kubeDoor安装的Victoria-Metrics,并且agent和master在同一个K8S时,可使用以下默认地址(注意认证信息),否则请填写实际的Victoria-Metrics地址。 31 | remoteWriteUrl: "http://monit:dduF1E3sj@victoria-metrics.kubedoor:8428/api/v1/write" # 注意:Victoria-Metrics-Cluster地址格式:http://你的vminsert地址:8480/insert/0/prometheus 32 | 33 | 34 | monit: 35 | # vmagent是比Prometheus性能更好,资源占用更小的指标采集组件。 36 | vmagent: 37 | enable: true 38 | 39 | # 用于Prometheus采集K8S监控数据指标,会安装到kubedoor命名空间。 40 | kube_state_metrics: 41 | enable: true 42 | version: v2.14.0 43 | 44 | # 用于Prometheus采集K8S节点数据指标,如果K8S节点已部署node-exporter可设置为false 45 | node_exporter: 46 | enable: true 47 | -------------------------------------------------------------------------------- /install/helm/kubedoor/values.yaml: -------------------------------------------------------------------------------- 1 | image: 2 | repository: swr.cn-south-1.myhuaweicloud.com/starsl.cn 3 | agent_build: python # 默认kubedoor-agent是Python的版本,改为"go"可切换为@comqx(https://github.com/comqx)开发维护的go版本(也可以安装后修改镜像标签或在WEBUI-agent管理中切换版本) 4 | kubedoor_agent_go_tag: 1.1.3-go 5 | kubedoor_agent_tag: 1.3.0 6 | kubedoor_master_tag: 1.3.0 7 | kubedoor_web_tag: 1.3.0 8 | kubedoor_alarm_tag: 1.2.0 9 | kubedoor_mcp_tag: 0.3.0 10 | 11 | grafana_plugins_init: 0.1.0 12 | grafana_oss: 11.4.0 13 | 14 | tsdb: 15 | type: "KubeDoor" 16 | 17 | clickhouse: 18 | enable: false 19 | 20 | kubedoor: 21 | agent: 22 | enable: false 23 | master: 24 | enable: false 25 | 26 | monit: 27 | vmagent: 28 | enable: false 29 | kube_state_metrics: 30 | enable: false 31 | node_exporter: 32 | enable: false 33 | -------------------------------------------------------------------------------- /install/kubedoor-web.dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/node:22-alpine AS builder 2 | ADD . /kubedoor-web/ 3 | WORKDIR /kubedoor-web 4 | # RUN npm install -g pnpm && pnpm install && npm run build 5 | RUN npm install -g pnpm --registry=https://registry.npmmirror.com && \ 6 | pnpm install --registry=https://registry.npmmirror.com && \ 7 | npm run build 8 | # FROM registry.cn-shenzhen.aliyuncs.com/starsl/nginx:1.24.0-alpine 9 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/nginx-ldap:1.27-alpine 10 | WORKDIR /www 11 | COPY --from=builder /kubedoor-web/dist dist/ 12 | -------------------------------------------------------------------------------- /install/sslgen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 证书请求文件配置 4 | expiredays=36500 #制定证书过期时间100年 5 | service="kubedoor-agent" 6 | namespace="kubedoor" 7 | svc="svc" 8 | cluster="cluster.local" 9 | 10 | mkdir -p ssl 11 | cd ssl 12 | 13 | cat > csr.conf < 镜像地址:comqx/kubedoor-agent:v1.0.2-go 4 | ``` 5 | 1. 新增pod删除功能 6 | 2. 新增pod label隔离功能 7 | ``` 8 | # 1.1.3-go 9 | > 镜像地址:comqx/kubedoor-agent:v1.1.3-go 10 | ``` 11 | 1. 新增管控模式 12 | 2. 完善jvm相关操作 13 | ``` -------------------------------------------------------------------------------- /src/kubedoor-agent-go/config/adminStruct.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "encoding/json" 5 | "sync" 6 | ) 7 | 8 | // AdmisRequestResult 定义返回的处理结果 9 | type AdmisRequestResult struct { 10 | Status int `json:"status"` 11 | Message string `json:"message"` 12 | } 13 | 14 | type AdmisRequestResultObj struct { 15 | Type string `json:"type"` 16 | RequestId string `json:"request_id"` 17 | DeployRes *json.RawMessage `json:"deploy_res"` 18 | } 19 | 20 | var ( 21 | RequestFutures = NewRequestFuturesMap() 22 | ) 23 | 24 | // RequestFuturesMap 是一个封装了 map 和同步机制的类型 25 | type RequestFuturesMap struct { 26 | mu sync.RWMutex // 读写锁 27 | futures map[string]chan *json.RawMessage // map 存储的实际数据 28 | } 29 | 30 | // NewRequestFuturesMap 创建一个新的 RequestFuturesMap 实例 31 | func NewRequestFuturesMap() *RequestFuturesMap { 32 | return &RequestFuturesMap{ 33 | futures: make(map[string]chan *json.RawMessage, 10), 34 | } 35 | } 36 | 37 | // Set 向 map 中添加一个键值对,使用写锁确保线程安全 38 | func (r *RequestFuturesMap) Set(key string, value chan *json.RawMessage) { 39 | r.mu.Lock() 40 | defer r.mu.Unlock() 41 | r.futures[key] = value 42 | } 43 | 44 | // Get 从 map 中获取一个值,使用读锁确保线程安全 45 | func (r *RequestFuturesMap) Get(key string) (chan *json.RawMessage, bool) { 46 | r.mu.RLock() 47 | defer r.mu.RUnlock() 48 | value, exists := r.futures[key] 49 | return value, exists 50 | } 51 | 52 | // Delete 从 map 中删除一个键值对,使用写锁确保线程安全 53 | func (r *RequestFuturesMap) Delete(key string) { 54 | r.mu.Lock() 55 | defer r.mu.Unlock() 56 | delete(r.futures, key) 57 | } 58 | 59 | // Size 获取 map 的大小,使用读锁确保线程安全 60 | func (r *RequestFuturesMap) Size() int { 61 | r.mu.RLock() 62 | defer r.mu.RUnlock() 63 | return len(r.futures) 64 | } 65 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/config/variables.go: -------------------------------------------------------------------------------- 1 | package config 2 | 3 | import ( 4 | "github.com/gorilla/websocket" 5 | "k8s.io/client-go/kubernetes" 6 | "os" 7 | ) 8 | 9 | var ( 10 | PROM_K8S_TAG_VALUE = os.Getenv("PROM_K8S_TAG_VALUE") 11 | KubeClient *kubernetes.Clientset 12 | WebSocketConcent *websocket.Conn // 你需要定义 WebSocketClient 或者其他的 WebSocket 客户端 13 | ) 14 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/go.mod: -------------------------------------------------------------------------------- 1 | module kubedoor-agent-go 2 | 3 | go 1.23.0 4 | 5 | toolchain go1.23.6 6 | 7 | require ( 8 | github.com/google/uuid v1.6.0 9 | github.com/gorilla/mux v1.8.1 10 | github.com/gorilla/websocket v1.5.3 11 | go.uber.org/zap v1.27.0 12 | k8s.io/api v0.32.2 13 | k8s.io/apimachinery v0.32.2 14 | k8s.io/client-go v0.32.2 15 | ) 16 | 17 | require ( 18 | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 19 | github.com/emicklei/go-restful/v3 v3.11.0 // indirect 20 | github.com/fxamacker/cbor/v2 v2.7.0 // indirect 21 | github.com/go-logr/logr v1.4.2 // indirect 22 | github.com/go-openapi/jsonpointer v0.21.0 // indirect 23 | github.com/go-openapi/jsonreference v0.20.2 // indirect 24 | github.com/go-openapi/swag v0.23.0 // indirect 25 | github.com/gogo/protobuf v1.3.2 // indirect 26 | github.com/golang/protobuf v1.5.4 // indirect 27 | github.com/google/gnostic-models v0.6.8 // indirect 28 | github.com/google/go-cmp v0.6.0 // indirect 29 | github.com/google/gofuzz v1.2.0 // indirect 30 | github.com/josharian/intern v1.0.0 // indirect 31 | github.com/json-iterator/go v1.1.12 // indirect 32 | github.com/mailru/easyjson v0.7.7 // indirect 33 | github.com/moby/spdystream v0.5.0 // indirect 34 | github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect 35 | github.com/modern-go/reflect2 v1.0.2 // indirect 36 | github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect 37 | github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect 38 | github.com/pkg/errors v0.9.1 // indirect 39 | github.com/spf13/pflag v1.0.5 // indirect 40 | github.com/x448/float16 v0.8.4 // indirect 41 | go.uber.org/multierr v1.10.0 // indirect 42 | golang.org/x/net v0.30.0 // indirect 43 | golang.org/x/oauth2 v0.23.0 // indirect 44 | golang.org/x/sys v0.26.0 // indirect 45 | golang.org/x/term v0.25.0 // indirect 46 | golang.org/x/text v0.19.0 // indirect 47 | golang.org/x/time v0.7.0 // indirect 48 | google.golang.org/protobuf v1.35.1 // indirect 49 | gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect 50 | gopkg.in/inf.v0 v0.9.1 // indirect 51 | gopkg.in/yaml.v3 v3.0.1 // indirect 52 | k8s.io/klog/v2 v2.130.1 // indirect 53 | k8s.io/kube-openapi v0.0.0-20241105132330-32ad38e42d3f // indirect 54 | k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 // indirect 55 | sigs.k8s.io/json v0.0.0-20241010143419-9aa6b5e7a4b3 // indirect 56 | sigs.k8s.io/structured-merge-diff/v4 v4.4.2 // indirect 57 | sigs.k8s.io/yaml v1.4.0 // indirect 58 | ) 59 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/k8sSet/k8sClient.go: -------------------------------------------------------------------------------- 1 | package k8sSet 2 | 3 | import ( 4 | "go.uber.org/zap" 5 | "k8s.io/client-go/kubernetes" 6 | "k8s.io/client-go/rest" 7 | "k8s.io/client-go/tools/clientcmd" 8 | "kubedoor-agent-go/config" 9 | "kubedoor-agent-go/utils" 10 | 11 | "log" 12 | "os" 13 | ) 14 | 15 | func init() { 16 | utils.InitLogger() // Initialize logger 17 | config.KubeClient = initKubeClient() 18 | } 19 | 20 | func initKubeClient() *kubernetes.Clientset { 21 | config, err := rest.InClusterConfig() 22 | if err != nil { 23 | utils.Logger.Warn("Failed to load incluster config", zap.Error(err)) 24 | kubeconfig := os.Getenv("KUBECONFIG") 25 | if kubeconfig == "" { 26 | kubeconfig = os.Getenv("HOME") + "/.kube/config" 27 | } 28 | config, err = clientcmd.BuildConfigFromFlags("", kubeconfig) 29 | if err != nil { 30 | utils.Logger.Fatal("Failed to load kubeconfig", zap.Error(err)) 31 | log.Fatalf("Failed to load kubeconfig: %v", err) 32 | } 33 | } 34 | 35 | clientset, err := kubernetes.NewForConfig(config) 36 | if err != nil { 37 | utils.Logger.Fatal("Failed to create kubernetes client", zap.Error(err)) 38 | log.Fatalf("Failed to create kubernetes client: %v", err) 39 | } 40 | 41 | utils.Logger.Info("Successfully initialized Kubernetes client") 42 | return clientset 43 | } 44 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "kubedoor-agent-go/agent" 5 | "kubedoor-agent-go/api" 6 | _ "kubedoor-agent-go/config" 7 | _ "kubedoor-agent-go/k8sSet" 8 | "kubedoor-agent-go/utils" 9 | ) 10 | 11 | func main() { 12 | 13 | utils.InitLogger() // Initialize logger 14 | go func() { 15 | api.StartAPI() 16 | }() 17 | //// Start PodMgr server in a goroutine 18 | //go func() { 19 | // podmgr.StartPodMgr() 20 | //}() 21 | agent.StartAgent() 22 | } 23 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/podmgr/autoJfr.go: -------------------------------------------------------------------------------- 1 | package podmgr 2 | 3 | import ( 4 | "fmt" 5 | "github.com/google/uuid" 6 | "kubedoor-agent-go/config" 7 | "net/http" 8 | "os" 9 | "time" 10 | ) 11 | 12 | // 处理自动 JFR 请求 13 | func autoJFRHandler(w http.ResponseWriter, r *http.Request) { 14 | ns := r.URL.Query().Get("ns") 15 | podName := r.URL.Query().Get("pod_name") 16 | env := r.URL.Query().Get("env") 17 | 18 | // Start JFR recording 19 | fileName := fmt.Sprintf("%s-%s-%s.jfr", env, ns, podName) 20 | command := fmt.Sprintf("jcmd 1 JFR.start duration=5m filename=/%s", fileName) 21 | status, _ := ExecuteCommand(command, podName, ns) 22 | if !status { 23 | http.Error(w, "Failed to start JFR", http.StatusInternalServerError) 24 | return 25 | } 26 | 27 | // Upload JFR file to OSS 28 | dlurl := fmt.Sprintf("%s/%s/jfr/%s", os.Getenv("OSS_URL"), env, fileName) 29 | command = fmt.Sprintf("curl -s -T /%s %s", fileName, dlurl) 30 | status, _ = ExecuteCommand(command, podName, ns) 31 | if !status { 32 | http.Error(w, "Failed to upload JFR file", http.StatusInternalServerError) 33 | return 34 | } 35 | 36 | // Create background task to upload JFR file 37 | taskID := uuid.New().String() 38 | config.TaskManagerObj.UpdateTask(taskID, &config.TaskResult{ 39 | Status: "processing", 40 | }) 41 | go func() { 42 | time.Sleep(2 * time.Minute) 43 | config.TaskManagerObj.UpdateTask(taskID, &config.TaskResult{ 44 | Status: "completed", 45 | File: dlurl, 46 | }) 47 | 48 | }() 49 | 50 | sendMd("JFR file uploaded successfully", env, ns, podName) 51 | w.WriteHeader(http.StatusOK) 52 | w.Write([]byte(fmt.Sprintf("JFR file available at %s", dlurl))) 53 | } 54 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/podmgr/autoJstack.go: -------------------------------------------------------------------------------- 1 | package podmgr 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | ) 8 | 9 | // 处理自动 JStack 请求 10 | func autoJStackHandler(w http.ResponseWriter, r *http.Request) { 11 | ns := r.URL.Query().Get("ns") 12 | podName := r.URL.Query().Get("pod_name") 13 | env := r.URL.Query().Get("env") 14 | 15 | // Execute jstack command 16 | fileName := fmt.Sprintf("%s-%s-%s.jstack", env, ns, podName) 17 | command := fmt.Sprintf("jstack -l 1 |tee /%s", fileName) 18 | status, _ := ExecuteCommand(command, podName, ns) 19 | if !status { 20 | http.Error(w, "Failed to execute jstack", http.StatusInternalServerError) 21 | return 22 | } 23 | 24 | // Upload the jstack file to OSS 25 | dlurl := fmt.Sprintf("%s/%s/jstack/%s", os.Getenv("OSS_URL"), env, fileName) 26 | command = fmt.Sprintf("curl -s -T /%s %s", fileName, dlurl) 27 | status, _ = ExecuteCommand(command, podName, ns) 28 | if !status { 29 | http.Error(w, "Failed to upload jstack file", http.StatusInternalServerError) 30 | return 31 | } 32 | 33 | sendMd("Jstack file uploaded successfully", env, ns, podName) 34 | w.WriteHeader(http.StatusOK) 35 | w.Write([]byte(fmt.Sprintf("Jstack file available at %s", dlurl))) 36 | } 37 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/podmgr/autoJvmMem.go: -------------------------------------------------------------------------------- 1 | package podmgr 2 | 3 | import ( 4 | "fmt" 5 | "os" 6 | 7 | "net/http" 8 | ) 9 | 10 | // 处理自动 JVM 内存请求 11 | func autoJvmMemHandler(w http.ResponseWriter, r *http.Request) { 12 | ns := r.URL.Query().Get("ns") 13 | podName := r.URL.Query().Get("pod_name") 14 | env := r.URL.Query().Get("env") 15 | 16 | // Execute jcmd memory command 17 | fileName := fmt.Sprintf("%s-%s-%s.mem", env, ns, podName) 18 | command := fmt.Sprintf("jcmd 1 VM.native_memory summary output=/%s", fileName) 19 | status, _ := ExecuteCommand(command, podName, ns) 20 | if !status { 21 | http.Error(w, "Failed to collect JVM memory statistics", http.StatusInternalServerError) 22 | return 23 | } 24 | // Upload the memory file to OSS 25 | dlurl := fmt.Sprintf("%s/%s/jvm_mem/%s", os.Getenv("OSS_URL"), env, fileName) 26 | command = fmt.Sprintf("curl -s -T /%s %s", fileName, dlurl) 27 | status, _ = ExecuteCommand(command, podName, ns) 28 | if !status { 29 | http.Error(w, "Failed to upload JVM memory file", http.StatusInternalServerError) 30 | return 31 | } 32 | 33 | sendMd("JVM memory statistics file uploaded successfully", env, ns, podName) 34 | w.WriteHeader(http.StatusOK) 35 | w.Write([]byte(fmt.Sprintf("JVM memory file available at %s", dlurl))) 36 | } 37 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/podmgr/autodump.go: -------------------------------------------------------------------------------- 1 | package podmgr 2 | 3 | import ( 4 | "fmt" 5 | "net/http" 6 | "os" 7 | ) 8 | 9 | // 处理自动 Dump 请求 10 | func autoDumpHandler(w http.ResponseWriter, r *http.Request) { 11 | ns := r.URL.Query().Get("ns") 12 | podName := r.URL.Query().Get("pod_name") 13 | env := r.URL.Query().Get("env") 14 | 15 | // Execute dump command 16 | fileName := fmt.Sprintf("%s-%s-%s.hprof", env, ns, podName) 17 | command := fmt.Sprintf("jmap -dump:format=b,file=/%s 1", fileName) 18 | status, _ := ExecuteCommand(command, podName, ns) 19 | if !status { 20 | http.Error(w, "Failed to execute jmap dump", http.StatusInternalServerError) 21 | return 22 | } 23 | 24 | // Upload the dump file to OSS 25 | dlurl := fmt.Sprintf("%s/%s/dump/%s", os.Getenv("OSS_URL"), env, fileName) 26 | command = fmt.Sprintf("curl -s -T /%s %s", fileName, dlurl) 27 | status, _ = ExecuteCommand(command, podName, ns) 28 | if !status { 29 | http.Error(w, "Failed to upload dump file", http.StatusInternalServerError) 30 | return 31 | } 32 | 33 | sendMd("Dump file uploaded successfully", env, ns, podName) 34 | w.WriteHeader(http.StatusOK) 35 | w.Write([]byte(fmt.Sprintf("Dump file available at %s", dlurl))) 36 | } 37 | 38 | // ExecuteCommand executes command in pod and returns success status and output 39 | func ExecuteCommand(command, podName, ns string) (bool, string) { 40 | // 41 | //// 准备执行命令 42 | //execOptions := &metav1.PodExecOptions{ 43 | // Command: []string{"/bin/sh", "-c", command}, 44 | // Stdin: false, 45 | // Stdout: true, 46 | // Stderr: true, 47 | // Tty: false, 48 | //} 49 | // 50 | //// 获取 Pod 执行请求 51 | //req := k8sSet.KubeClient.CoreV1().Pods(ns).GetExec(podName, execOptions) 52 | // 53 | //// 捕获输出 54 | //var stdout, stderr bytes.Buffer 55 | //err = req.StreamOptions().Stdout(&stdout).Stderr(&stderr).Stream(context.Background()) 56 | //if err != nil { 57 | // log.Printf("Error executing command: %v", err) 58 | // return false, err.Error() 59 | //} 60 | // 61 | //// 返回输出信息 62 | //out := stdout.String() 63 | //if stderr.Len() > 0 { 64 | // out += "\n" + stderr.String() 65 | //} 66 | 67 | //return true, out 68 | return true, "" 69 | } 70 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/requirements.txt: -------------------------------------------------------------------------------- 1 | kubernetes 2 | kubernetes_asyncio 3 | loguru 4 | asyncio 5 | aiohttp 6 | fastapi 7 | uvicorn -------------------------------------------------------------------------------- /src/kubedoor-agent-go/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | nohup python3 /app/pod-mgr.py & 3 | /kubedoor-agent -------------------------------------------------------------------------------- /src/kubedoor-agent-go/tls.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIELTCCAxWgAwIBAgIJAKis/ihR+CRtMA0GCSqGSIb3DQEBCwUAMCYxJDAiBgNV 3 | BAMMG2t1YmVkb29yLWFnZW50Lmt1YmVkb29yLnN2YzAgFw0yNTAzMTAwMzI0NDBa 4 | GA8yMTI1MDIxNDAzMjQ0MFowcTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAlNaMQsw 5 | CQYDVQQHDAJTWjESMBAGA1UECgwJU3RhcnNMLmNuMRIwEAYDVQQLDAlTdGFyc0wu 6 | Y24xIDAeBgNVBAMMF2t1YmVkb29yLWFnZW50Lmt1YmVkb29yMIIBIjANBgkqhkiG 7 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSMAwg8focm86WqsjKpRMj7NOONcXPKcEpVo 8 | bypXFkzWJvmpHLK5e/iSCWJ0my0ip2q0WRXzo9bv/TT2NgauDJz+L3D9XH4b+2ug 9 | 97u8CbWCLmuscTPIhPs4mj3iQC0dFzC/86xlmmNcF/o3swpSPejxn4YRrzRpHVjy 10 | DNbN+5PtqCv1vuk9OyXcL1QNLNiW1tmo2cwSxS9D281rU+Earf9FgaYJTd3KLo1s 11 | nZsWpRUCKBwQIhHreeknMqTiAv8CVNcFEYOAu0Xcvk7rZx9hEnILuLr+mwUyYKpZ 12 | Y1YjAS7rUcCiML+OZxANNaz9dagiO3CmLbZYYxx+pAa+7TM23wIDAQABo4IBDzCC 13 | AQswVgYDVR0jBE8wTYAU/oOFa1haaLCt6tsGOAp+Q53TFnmhKqQoMCYxJDAiBgNV 14 | BAMMG2t1YmVkb29yLWFnZW50Lmt1YmVkb29yLnN2Y4IJAI5Ow/BtqHBiMAkGA1Ud 15 | EwQCMAAwCwYDVR0PBAQDAgQwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD 16 | AjB6BgNVHREEczBxgg5rdWJlZG9vci1hZ2VudIIXa3ViZWRvb3ItYWdlbnQua3Vi 17 | ZWRvb3KCG2t1YmVkb29yLWFnZW50Lmt1YmVkb29yLnN2Y4Ipa3ViZWRvb3ItYWdl 18 | bnQua3ViZWRvb3Iuc3ZjLmNsdXN0ZXIubG9jYWwwDQYJKoZIhvcNAQELBQADggEB 19 | AAWJZLuVNxBbJqctdQ+KhT4KEveWN5XawzZ0WwOitAxZFctUwR8O6EwKaZ3h5pfk 20 | +JYDOuDwuErZQCjxzR4dBz/4jMXc00y9Ib1kVQ1Z93mBkh3dnNaFPyqhyuOMvJ4b 21 | QKKQNJIF9oOFLzcI6ceZVc8Ses+4YmDQpV3u4tPIr+cuN/7u7k3zaGQ5dhx2HOdo 22 | XnBoD+GyKigJvwXhtl+7uu7acK46p3iO0ELpG97qNIowmtXmPSmLl/KZ02GtRfW3 23 | BrzxeqlnsD37J1iAPQH4mv1IgaaLOez/NvDzbOi1jE+Sexq8o/zigMiYjXe8XjAh 24 | PTiBKLYkqRZsNWNFdxKa9l4= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/tls.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvSMAwg8focm86WqsjKpRMj7NOONcXPKcEpVobypXFkzWJvmp 3 | HLK5e/iSCWJ0my0ip2q0WRXzo9bv/TT2NgauDJz+L3D9XH4b+2ug97u8CbWCLmus 4 | cTPIhPs4mj3iQC0dFzC/86xlmmNcF/o3swpSPejxn4YRrzRpHVjyDNbN+5PtqCv1 5 | vuk9OyXcL1QNLNiW1tmo2cwSxS9D281rU+Earf9FgaYJTd3KLo1snZsWpRUCKBwQ 6 | IhHreeknMqTiAv8CVNcFEYOAu0Xcvk7rZx9hEnILuLr+mwUyYKpZY1YjAS7rUcCi 7 | ML+OZxANNaz9dagiO3CmLbZYYxx+pAa+7TM23wIDAQABAoIBAFJRpcbQpkfYcix1 8 | jVw71NM1mkSkUFL0FRHRjX60wuqlzp9wEja3Yxud+JG1FGNlpauQOaZ8c2pf5lwi 9 | bPbeuWor+kXTu7JCARPQqGKqhxECuwJRQuCSVTfrz5ryTEL6X6r0QNdhtWcYz8Bv 10 | 20ZFu73OYTu5MoE7InTvfYoxA732yK90lwB8KVLga2VO20XClRzcEGT2XIo/E5oa 11 | L1/3AwCN9u5beFUFSwS7sE9wddTwkXeJ0KPEFt1y2phnL++LVaTZzDbJ3dmNB1NP 12 | p8IHH+m0X1l97CpKFsfRDNdVJkHTq9ac1Rn3kNYpRv6jzTrBU0ZVVMbzRMt8gY9U 13 | An0Nk8ECgYEA59KggkTG5ck0rcnBS3HPSW5hpHTHHUUPtKHDu9HR33mGcoPHrmCk 14 | lBpeEXDV2vNerO4PzH4Hd3XyLX+gbDR/FtAliOU4GzY92UXgvl+/Otz9Z3D69EmV 15 | bCrV1hUnSLsIl+U2gnJcw+o8AarAFVcrwv9q+xmr47eUnjsLUkVEUrkCgYEA0Ny2 16 | lJEeDaTnZWpT5DBNvLOq+7vMwzxP+LBrLPU0N5U/pAg41XvEJG8YJ9immXOMap84 17 | Kvas1t6BjCPxCRQCAmutIbNm49HUoiTB8CDEQXws3nTvszlKt13cFPJVgJHzzNoQ 18 | LPcsTl4B6hXCi969uhlyBW9edoxJVILHpBNO6lcCgYBfaiPCOkia/0t9VBMI2Fj2 19 | 4kWyCJaDh49FS2digKOfFUevDmo7bW+PvaKGDykWKyEGkB1Uj3LHSnZZH7SJlLnS 20 | S+2HAMEtAhBGwyoTcRkmQxrRXoEL1tV3ZdIJgT9gAgsxaZgb7LIduOTl0r+oiO5s 21 | HfCMVS6YVVEIJ0krnXLXkQKBgQC8fpTgm98tnSegZUd05wshRF0Jd0Gi6WmbHUx8 22 | dIc9qpqW5Ty1nk80OnbobyRb1OZiy3MbgygVexYbbcx4zu/JU3gatBglfxeRhe7p 23 | UgkMuI6d7ZbufsQpnLGkzdfQgugudpamniQETd8Yba74IHvF2nUG5q2v+4eql6Sp 24 | NSvBXQKBgDiJJsrpmV4gPIb7FrrprRB9uyBvnt7CNN3khkzFejFcdCz0zIN13i5W 25 | bwl7Y2hfD1o0JZ+taZDZhsdDGG+KuWRyjg8/SbvQwuPFZUMjtb21pmGrPE1+V0nb 26 | Z49+XfGJkhXZyuhbwuBD0twy08KtNa8drnG1KAHg8AvENdNpfkAA 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /src/kubedoor-agent-go/version: -------------------------------------------------------------------------------- 1 | 1.3.0-go -------------------------------------------------------------------------------- /src/kubedoor-agent/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/python:3.11-alpine 2 | 3 | # 设置工作目录 4 | WORKDIR /app 5 | 6 | # 拷贝 Python 脚本到容器中 7 | COPY utils.py kubedoor-agent.py pod-mgr.py version requirements.txt /app/ 8 | 9 | COPY tls.crt tls.key /serving-certs/ 10 | 11 | RUN pip install --no-cache-dir -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ 12 | 13 | # 安装 runit 和其他必要工具 14 | RUN sed -i 's/dl-cdn.alpinelinux.org/repo.huaweicloud.com/g' /etc/apk/repositories && apk add --no-cache runit bash 15 | 16 | # 创建服务目录 17 | RUN mkdir -p /etc/service/kubedoor-agent /etc/service/pod-mgr 18 | 19 | # 配置 kubedoor-agent 的 run 脚本 20 | RUN echo -e '#!/bin/sh\nexec python3 /app/kubedoor-agent.py' > /etc/service/kubedoor-agent/run && \ 21 | chmod +x /etc/service/kubedoor-agent/run 22 | 23 | 24 | # 配置 pod-mgr 的 run 脚本 25 | RUN echo -e '#!/bin/sh\nexec python3 /app/pod-mgr.py' > /etc/service/pod-mgr/run && \ 26 | chmod +x /etc/service/pod-mgr/run 27 | 28 | # 启动 runit 29 | CMD ["runsvdir", "/etc/service"] 30 | -------------------------------------------------------------------------------- /src/kubedoor-agent/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-agent/__init__.py -------------------------------------------------------------------------------- /src/kubedoor-agent/requirements.txt: -------------------------------------------------------------------------------- 1 | kubernetes 2 | kubernetes_asyncio 3 | loguru 4 | asyncio 5 | aiohttp 6 | fastapi 7 | uvicorn 8 | pytz -------------------------------------------------------------------------------- /src/kubedoor-agent/tls.crt: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIELTCCAxWgAwIBAgIJAKis/ihR+CRtMA0GCSqGSIb3DQEBCwUAMCYxJDAiBgNV 3 | BAMMG2t1YmVkb29yLWFnZW50Lmt1YmVkb29yLnN2YzAgFw0yNTAzMTAwMzI0NDBa 4 | GA8yMTI1MDIxNDAzMjQ0MFowcTELMAkGA1UEBhMCQ04xCzAJBgNVBAgMAlNaMQsw 5 | CQYDVQQHDAJTWjESMBAGA1UECgwJU3RhcnNMLmNuMRIwEAYDVQQLDAlTdGFyc0wu 6 | Y24xIDAeBgNVBAMMF2t1YmVkb29yLWFnZW50Lmt1YmVkb29yMIIBIjANBgkqhkiG 7 | 9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvSMAwg8focm86WqsjKpRMj7NOONcXPKcEpVo 8 | bypXFkzWJvmpHLK5e/iSCWJ0my0ip2q0WRXzo9bv/TT2NgauDJz+L3D9XH4b+2ug 9 | 97u8CbWCLmuscTPIhPs4mj3iQC0dFzC/86xlmmNcF/o3swpSPejxn4YRrzRpHVjy 10 | DNbN+5PtqCv1vuk9OyXcL1QNLNiW1tmo2cwSxS9D281rU+Earf9FgaYJTd3KLo1s 11 | nZsWpRUCKBwQIhHreeknMqTiAv8CVNcFEYOAu0Xcvk7rZx9hEnILuLr+mwUyYKpZ 12 | Y1YjAS7rUcCiML+OZxANNaz9dagiO3CmLbZYYxx+pAa+7TM23wIDAQABo4IBDzCC 13 | AQswVgYDVR0jBE8wTYAU/oOFa1haaLCt6tsGOAp+Q53TFnmhKqQoMCYxJDAiBgNV 14 | BAMMG2t1YmVkb29yLWFnZW50Lmt1YmVkb29yLnN2Y4IJAI5Ow/BtqHBiMAkGA1Ud 15 | EwQCMAAwCwYDVR0PBAQDAgQwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD 16 | AjB6BgNVHREEczBxgg5rdWJlZG9vci1hZ2VudIIXa3ViZWRvb3ItYWdlbnQua3Vi 17 | ZWRvb3KCG2t1YmVkb29yLWFnZW50Lmt1YmVkb29yLnN2Y4Ipa3ViZWRvb3ItYWdl 18 | bnQua3ViZWRvb3Iuc3ZjLmNsdXN0ZXIubG9jYWwwDQYJKoZIhvcNAQELBQADggEB 19 | AAWJZLuVNxBbJqctdQ+KhT4KEveWN5XawzZ0WwOitAxZFctUwR8O6EwKaZ3h5pfk 20 | +JYDOuDwuErZQCjxzR4dBz/4jMXc00y9Ib1kVQ1Z93mBkh3dnNaFPyqhyuOMvJ4b 21 | QKKQNJIF9oOFLzcI6ceZVc8Ses+4YmDQpV3u4tPIr+cuN/7u7k3zaGQ5dhx2HOdo 22 | XnBoD+GyKigJvwXhtl+7uu7acK46p3iO0ELpG97qNIowmtXmPSmLl/KZ02GtRfW3 23 | BrzxeqlnsD37J1iAPQH4mv1IgaaLOez/NvDzbOi1jE+Sexq8o/zigMiYjXe8XjAh 24 | PTiBKLYkqRZsNWNFdxKa9l4= 25 | -----END CERTIFICATE----- 26 | -------------------------------------------------------------------------------- /src/kubedoor-agent/tls.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAvSMAwg8focm86WqsjKpRMj7NOONcXPKcEpVobypXFkzWJvmp 3 | HLK5e/iSCWJ0my0ip2q0WRXzo9bv/TT2NgauDJz+L3D9XH4b+2ug97u8CbWCLmus 4 | cTPIhPs4mj3iQC0dFzC/86xlmmNcF/o3swpSPejxn4YRrzRpHVjyDNbN+5PtqCv1 5 | vuk9OyXcL1QNLNiW1tmo2cwSxS9D281rU+Earf9FgaYJTd3KLo1snZsWpRUCKBwQ 6 | IhHreeknMqTiAv8CVNcFEYOAu0Xcvk7rZx9hEnILuLr+mwUyYKpZY1YjAS7rUcCi 7 | ML+OZxANNaz9dagiO3CmLbZYYxx+pAa+7TM23wIDAQABAoIBAFJRpcbQpkfYcix1 8 | jVw71NM1mkSkUFL0FRHRjX60wuqlzp9wEja3Yxud+JG1FGNlpauQOaZ8c2pf5lwi 9 | bPbeuWor+kXTu7JCARPQqGKqhxECuwJRQuCSVTfrz5ryTEL6X6r0QNdhtWcYz8Bv 10 | 20ZFu73OYTu5MoE7InTvfYoxA732yK90lwB8KVLga2VO20XClRzcEGT2XIo/E5oa 11 | L1/3AwCN9u5beFUFSwS7sE9wddTwkXeJ0KPEFt1y2phnL++LVaTZzDbJ3dmNB1NP 12 | p8IHH+m0X1l97CpKFsfRDNdVJkHTq9ac1Rn3kNYpRv6jzTrBU0ZVVMbzRMt8gY9U 13 | An0Nk8ECgYEA59KggkTG5ck0rcnBS3HPSW5hpHTHHUUPtKHDu9HR33mGcoPHrmCk 14 | lBpeEXDV2vNerO4PzH4Hd3XyLX+gbDR/FtAliOU4GzY92UXgvl+/Otz9Z3D69EmV 15 | bCrV1hUnSLsIl+U2gnJcw+o8AarAFVcrwv9q+xmr47eUnjsLUkVEUrkCgYEA0Ny2 16 | lJEeDaTnZWpT5DBNvLOq+7vMwzxP+LBrLPU0N5U/pAg41XvEJG8YJ9immXOMap84 17 | Kvas1t6BjCPxCRQCAmutIbNm49HUoiTB8CDEQXws3nTvszlKt13cFPJVgJHzzNoQ 18 | LPcsTl4B6hXCi969uhlyBW9edoxJVILHpBNO6lcCgYBfaiPCOkia/0t9VBMI2Fj2 19 | 4kWyCJaDh49FS2digKOfFUevDmo7bW+PvaKGDykWKyEGkB1Uj3LHSnZZH7SJlLnS 20 | S+2HAMEtAhBGwyoTcRkmQxrRXoEL1tV3ZdIJgT9gAgsxaZgb7LIduOTl0r+oiO5s 21 | HfCMVS6YVVEIJ0krnXLXkQKBgQC8fpTgm98tnSegZUd05wshRF0Jd0Gi6WmbHUx8 22 | dIc9qpqW5Ty1nk80OnbobyRb1OZiy3MbgygVexYbbcx4zu/JU3gatBglfxeRhe7p 23 | UgkMuI6d7ZbufsQpnLGkzdfQgugudpamniQETd8Yba74IHvF2nUG5q2v+4eql6Sp 24 | NSvBXQKBgDiJJsrpmV4gPIb7FrrprRB9uyBvnt7CNN3khkzFejFcdCz0zIN13i5W 25 | bwl7Y2hfD1o0JZ+taZDZhsdDGG+KuWRyjg8/SbvQwuPFZUMjtb21pmGrPE1+V0nb 26 | Z49+XfGJkhXZyuhbwuBD0twy08KtNa8drnG1KAHg8AvENdNpfkAA 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /src/kubedoor-agent/version: -------------------------------------------------------------------------------- 1 | 1.3.2 -------------------------------------------------------------------------------- /src/kubedoor-alarm/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/python:3.11-alpine 2 | ADD . / 3 | WORKDIR / 4 | RUN pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ --no-cache-dir 5 | EXPOSE 80 6 | CMD ["python3", "/kubedoor-alarm.py"] 7 | -------------------------------------------------------------------------------- /src/kubedoor-alarm/build.sh: -------------------------------------------------------------------------------- 1 | docker build -t swr.cn-south-1.myhuaweicloud.com/starsl.cn/kubedoor-alarm:latest . 2 | docker push swr.cn-south-1.myhuaweicloud.com/starsl.cn/kubedoor-alarm:latest 3 | -------------------------------------------------------------------------------- /src/kubedoor-alarm/requirements.txt: -------------------------------------------------------------------------------- 1 | flask 2 | requests 3 | clickhouse-pool -------------------------------------------------------------------------------- /src/kubedoor-alarm/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | # 环境变量 4 | CK_DATABASE = os.environ.get('CK_DATABASE') 5 | CK_HOST = os.environ.get('CK_HOST') 6 | CK_HTTP_PORT = os.environ.get('CK_HTTP_PORT') 7 | CK_PASSWORD = os.environ.get('CK_PASSWORD') 8 | CK_PORT = os.environ.get('CK_PORT') 9 | CK_USER = os.environ.get('CK_USER') 10 | MSG_TOKEN = os.environ.get('MSG_TOKEN') 11 | MSG_TYPE = os.environ.get('MSG_TYPE') 12 | PROM_K8S_TAG_KEY = os.environ.get('PROM_K8S_TAG_KEY') 13 | DEFAULT_AT = os.environ.get('DEFAULT_AT') 14 | ALERTMANAGER_EXTURL = os.environ.get('ALERTMANAGER_EXTURL') 15 | LOG_LEVEL = os.environ.get('LOG_LEVEL', 'INFO') 16 | -------------------------------------------------------------------------------- /src/kubedoor-master/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/python:3.11-alpine 2 | ADD . / 3 | WORKDIR / 4 | RUN pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ --no-cache-dir 5 | EXPOSE 80 6 | CMD ["python3", "/kubedoor-master.py"] 7 | -------------------------------------------------------------------------------- /src/kubedoor-master/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-master/__init__.py -------------------------------------------------------------------------------- /src/kubedoor-master/requirements.txt: -------------------------------------------------------------------------------- 1 | loguru 2 | asyncio 3 | aiohttp 4 | requests 5 | clickhouse_driver -------------------------------------------------------------------------------- /src/kubedoor-mcp/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/python:3.11-alpine 2 | ADD . / 3 | WORKDIR / 4 | RUN pip3 install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple/ --no-cache-dir 5 | EXPOSE 8000 6 | CMD ["python3", "/kubedoor-mcp.py"] 7 | -------------------------------------------------------------------------------- /src/kubedoor-mcp/requirements.txt: -------------------------------------------------------------------------------- 1 | httpx 2 | fastmcp -------------------------------------------------------------------------------- /src/kubedoor-web/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | not ie 11 -------------------------------------------------------------------------------- /src/kubedoor-web/.dockerignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | .eslintcache 7 | report.html 8 | 9 | yarn.lock 10 | npm-debug.log* 11 | .pnpm-error.log* 12 | .pnpm-debug.log 13 | tests/**/coverage/ 14 | 15 | # Editor directories and files 16 | .idea 17 | *.suo 18 | *.ntvs* 19 | *.njsproj 20 | *.sln 21 | tsconfig.tsbuildinfo 22 | -------------------------------------------------------------------------------- /src/kubedoor-web/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /src/kubedoor-web/.env.development: -------------------------------------------------------------------------------- 1 | # 平台本地运行端口号 2 | VITE_PORT = 8848 3 | 4 | # 开发环境读取配置文件路径 5 | VITE_PUBLIC_PATH = / 6 | 7 | # 开发环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数") 8 | VITE_ROUTER_HISTORY = "hash" 9 | -------------------------------------------------------------------------------- /src/kubedoor-web/.env.production: -------------------------------------------------------------------------------- 1 | # 线上环境平台打包路径 2 | VITE_PUBLIC_PATH = / 3 | 4 | # 线上环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数") 5 | VITE_ROUTER_HISTORY = "hash" 6 | 7 | # 是否在打包时使用cdn替换本地库 替换 true 不替换 false 8 | VITE_CDN = false 9 | 10 | # 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件) 11 | # 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 12 | # 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 13 | VITE_COMPRESSION = "none" -------------------------------------------------------------------------------- /src/kubedoor-web/.env.staging: -------------------------------------------------------------------------------- 1 | # 预发布也需要生产环境的行为 2 | # https://cn.vitejs.dev/guide/env-and-mode.html#modes 3 | # NODE_ENV = development 4 | 5 | VITE_PUBLIC_PATH = / 6 | 7 | # 预发布环境路由历史模式(Hash模式传"hash"、HTML5模式传"h5"、Hash模式带base参数传"hash,base参数"、HTML5模式带base参数传"h5,base参数") 8 | VITE_ROUTER_HISTORY = "hash" 9 | 10 | # 是否在打包时使用cdn替换本地库 替换 true 不替换 false 11 | VITE_CDN = true 12 | 13 | # 是否启用gzip压缩或brotli压缩(分两种情况,删除原始文件和不删除原始文件) 14 | # 压缩时不删除原始文件的配置:gzip、brotli、both(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 15 | # 压缩时删除原始文件的配置:gzip-clear、brotli-clear、both-clear(同时开启 gzip 与 brotli 压缩)、none(不开启压缩,默认) 16 | VITE_COMPRESSION = "none" 17 | -------------------------------------------------------------------------------- /src/kubedoor-web/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | dist 4 | dist-ssr 5 | *.local 6 | .eslintcache 7 | report.html 8 | vite.config.*.timestamp* 9 | 10 | yarn.lock 11 | npm-debug.log* 12 | .pnpm-error.log* 13 | .pnpm-debug.log 14 | tests/**/coverage/ 15 | 16 | # Editor directories and files 17 | .idea 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | tsconfig.tsbuildinfo -------------------------------------------------------------------------------- /src/kubedoor-web/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/.gitkeep -------------------------------------------------------------------------------- /src/kubedoor-web/.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # shellcheck source=./_/husky.sh 4 | . "$(dirname "$0")/_/husky.sh" 5 | 6 | PATH="/usr/local/bin:$PATH" 7 | 8 | npx --no-install commitlint --edit "$1" -------------------------------------------------------------------------------- /src/kubedoor-web/.husky/common.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | command_exists () { 3 | command -v "$1" >/dev/null 2>&1 4 | } 5 | 6 | # Workaround for Windows 10, Git Bash and Pnpm 7 | if command_exists winpty && test -t 1; then 8 | exec < /dev/tty 9 | fi 10 | -------------------------------------------------------------------------------- /src/kubedoor-web/.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | . "$(dirname "$0")/common.sh" 4 | 5 | [ -n "$CI" ] && exit 0 6 | 7 | PATH="/usr/local/bin:$PATH" 8 | 9 | # Perform lint check on files in the staging area through .lintstagedrc configuration 10 | pnpm exec lint-staged -------------------------------------------------------------------------------- /src/kubedoor-web/.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{js,jsx,ts,tsx}": [ 3 | "prettier --cache --ignore-unknown --write", 4 | "eslint --cache --fix" 5 | ], 6 | "{!(package)*.json,*.code-snippets,.!({browserslist,npm,nvm})*rc}": [ 7 | "prettier --cache --write--parser json" 8 | ], 9 | "package.json": ["prettier --cache --write"], 10 | "*.vue": [ 11 | "prettier --write", 12 | "eslint --cache --fix", 13 | "stylelint --fix --allow-empty-input" 14 | ], 15 | "*.{css,scss,html}": [ 16 | "prettier --cache --ignore-unknown --write", 17 | "stylelint --fix --allow-empty-input" 18 | ], 19 | "*.md": ["prettier --cache --ignore-unknown --write"] 20 | } 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/.markdownlint.json: -------------------------------------------------------------------------------- 1 | { 2 | "default": true, 3 | "MD003": false, 4 | "MD033": false, 5 | "MD013": false, 6 | "MD001": false, 7 | "MD025": false, 8 | "MD024": false, 9 | "MD007": { "indent": 4 }, 10 | "no-hard-tabs": false 11 | } 12 | -------------------------------------------------------------------------------- /src/kubedoor-web/.npmrc: -------------------------------------------------------------------------------- 1 | shell-emulator=true 2 | shamefully-hoist=true 3 | enable-pre-post-scripts=false 4 | strict-peer-dependencies=false -------------------------------------------------------------------------------- /src/kubedoor-web/.nvmrc: -------------------------------------------------------------------------------- 1 | v20.15.0 -------------------------------------------------------------------------------- /src/kubedoor-web/.prettierrc.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import("prettier").Config} */ 4 | export default { 5 | bracketSpacing: true, 6 | singleQuote: false, 7 | arrowParens: "avoid", 8 | trailingComma: "none" 9 | }; 10 | -------------------------------------------------------------------------------- /src/kubedoor-web/.stylelintignore: -------------------------------------------------------------------------------- 1 | /dist/* 2 | /public/* 3 | public/* 4 | src/style/reset.scss -------------------------------------------------------------------------------- /src/kubedoor-web/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/node:22-alpine AS builder 2 | ADD . /kubedoor-web/ 3 | WORKDIR /kubedoor-web 4 | # RUN npm install -g pnpm && pnpm install && npm run build 5 | RUN npm install -g pnpm --registry=https://registry.npmmirror.com && \ 6 | pnpm install --registry=https://registry.npmmirror.com && \ 7 | npm run build 8 | # FROM registry.cn-shenzhen.aliyuncs.com/starsl/nginx:1.24.0-alpine 9 | FROM registry.cn-shenzhen.aliyuncs.com/starsl/nginx-ldap:1.27-alpine 10 | WORKDIR /www 11 | COPY --from=builder /kubedoor-web/dist dist/ -------------------------------------------------------------------------------- /src/kubedoor-web/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020-present, pure-admin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/kubedoor-web/README.md: -------------------------------------------------------------------------------- 1 |

花折 - KubeDoor

2 | 3 | ## 介绍 4 | 5 | node版本 >= "^18.18.0 || ^20.9.0 || >=21.1.0" 6 | 7 | ## 命令 8 | 9 | ```bash 10 | # 安装 pnpm 11 | npm install -g pnpm 12 | 13 | # 安装依赖 14 | pnpm install 15 | 16 | # 格式化 17 | pnpm prettier --write . 18 | pnpm prettier --write .\src\views\monit\index.vue 19 | 20 | # 启动 21 | pnpm dev 22 | # 打包 23 | npm run build 24 | ``` 25 | -------------------------------------------------------------------------------- /src/kubedoor-web/build/cdn.ts: -------------------------------------------------------------------------------- 1 | import { Plugin as importToCDN } from "vite-plugin-cdn-import"; 2 | 3 | /** 4 | * @description 打包时采用`cdn`模式,仅限外网使用(默认不采用,如果需要采用cdn模式,请在 .env.production 文件,将 VITE_CDN 设置成true) 5 | * 平台采用国内cdn:https://www.bootcdn.cn,当然你也可以选择 https://unpkg.com 或者 https://www.jsdelivr.com 6 | * 注意:上面提到的仅限外网使用也不是完全肯定的,如果你们公司内网部署的有相关js、css文件,也可以将下面配置对应改一下,整一套内网版cdn 7 | */ 8 | export const cdn = importToCDN({ 9 | //(prodUrl解释: name: 对应下面modules的name,version: 自动读取本地package.json中dependencies依赖中对应包的版本号,path: 对应下面modules的path,当然也可写完整路径,会替换prodUrl) 10 | prodUrl: "https://cdn.bootcdn.net/ajax/libs/{name}/{version}/{path}", 11 | modules: [ 12 | { 13 | name: "vue", 14 | var: "Vue", 15 | path: "vue.global.prod.min.js" 16 | }, 17 | { 18 | name: "vue-router", 19 | var: "VueRouter", 20 | path: "vue-router.global.min.js" 21 | }, 22 | { 23 | name: "vue-i18n", 24 | var: "VueI18n", 25 | path: "vue-i18n.runtime.global.prod.min.js" 26 | }, 27 | // 项目中没有直接安装vue-demi,但是pinia用到了,所以需要在引入pinia前引入vue-demi(https://github.com/vuejs/pinia/blob/v2/packages/pinia/package.json#L77) 28 | { 29 | name: "vue-demi", 30 | var: "VueDemi", 31 | path: "index.iife.min.js" 32 | }, 33 | { 34 | name: "pinia", 35 | var: "Pinia", 36 | path: "pinia.iife.min.js" 37 | }, 38 | { 39 | name: "element-plus", 40 | var: "ElementPlus", 41 | path: "index.full.min.js", 42 | css: "index.min.css" 43 | }, 44 | { 45 | name: "axios", 46 | var: "axios", 47 | path: "axios.min.js" 48 | }, 49 | { 50 | name: "dayjs", 51 | var: "dayjs", 52 | path: "dayjs.min.js" 53 | }, 54 | { 55 | name: "echarts", 56 | var: "echarts", 57 | path: "echarts.min.js" 58 | } 59 | ] 60 | }); 61 | -------------------------------------------------------------------------------- /src/kubedoor-web/build/compress.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from "vite"; 2 | import { isArray } from "@pureadmin/utils"; 3 | import compressPlugin from "vite-plugin-compression"; 4 | 5 | export const configCompressPlugin = ( 6 | compress: ViteCompression 7 | ): Plugin | Plugin[] => { 8 | if (compress === "none") return null; 9 | 10 | const gz = { 11 | // 生成的压缩包后缀 12 | ext: ".gz", 13 | // 体积大于threshold才会被压缩 14 | threshold: 0, 15 | // 默认压缩.js|mjs|json|css|html后缀文件,设置成true,压缩全部文件 16 | filter: () => true, 17 | // 压缩后是否删除原始文件 18 | deleteOriginFile: false 19 | }; 20 | const br = { 21 | ext: ".br", 22 | algorithm: "brotliCompress", 23 | threshold: 0, 24 | filter: () => true, 25 | deleteOriginFile: false 26 | }; 27 | 28 | const codeList = [ 29 | { k: "gzip", v: gz }, 30 | { k: "brotli", v: br }, 31 | { k: "both", v: [gz, br] } 32 | ]; 33 | 34 | const plugins: Plugin[] = []; 35 | 36 | codeList.forEach(item => { 37 | if (compress.includes(item.k)) { 38 | if (compress.includes("clear")) { 39 | if (isArray(item.v)) { 40 | item.v.forEach(vItem => { 41 | plugins.push( 42 | compressPlugin(Object.assign(vItem, { deleteOriginFile: true })) 43 | ); 44 | }); 45 | } else { 46 | plugins.push( 47 | compressPlugin(Object.assign(item.v, { deleteOriginFile: true })) 48 | ); 49 | } 50 | } else { 51 | if (isArray(item.v)) { 52 | item.v.forEach(vItem => { 53 | plugins.push(compressPlugin(vItem)); 54 | }); 55 | } else { 56 | plugins.push(compressPlugin(item.v)); 57 | } 58 | } 59 | } 60 | }); 61 | 62 | return plugins; 63 | }; 64 | -------------------------------------------------------------------------------- /src/kubedoor-web/build/info.ts: -------------------------------------------------------------------------------- 1 | import type { Plugin } from "vite"; 2 | import { getPackageSize } from "./utils"; 3 | import dayjs, { type Dayjs } from "dayjs"; 4 | import duration from "dayjs/plugin/duration"; 5 | import gradientString from "gradient-string"; 6 | import boxen, { type Options as BoxenOptions } from "boxen"; 7 | dayjs.extend(duration); 8 | 9 | const welcomeMessage = gradientString("cyan", "magenta").multiline( 10 | `您好! 欢迎使用 pure-admin 开源项目\n我们为您精心准备了下面两个贴心的保姆级文档\nhttps://pure-admin.github.io/pure-admin-doc\nhttps://pure-admin-utils.netlify.app` 11 | ); 12 | 13 | const boxenOptions: BoxenOptions = { 14 | padding: 0.5, 15 | borderColor: "cyan", 16 | borderStyle: "round" 17 | }; 18 | 19 | export function viteBuildInfo(): Plugin { 20 | let config: { command: string }; 21 | let startTime: Dayjs; 22 | let endTime: Dayjs; 23 | let outDir: string; 24 | return { 25 | name: "vite:buildInfo", 26 | configResolved(resolvedConfig) { 27 | config = resolvedConfig; 28 | outDir = resolvedConfig.build?.outDir ?? "dist"; 29 | }, 30 | buildStart() { 31 | console.log(boxen(welcomeMessage, boxenOptions)); 32 | if (config.command === "build") { 33 | startTime = dayjs(new Date()); 34 | } 35 | }, 36 | closeBundle() { 37 | if (config.command === "build") { 38 | endTime = dayjs(new Date()); 39 | getPackageSize({ 40 | folder: outDir, 41 | callback: (size: string) => { 42 | console.log( 43 | boxen( 44 | gradientString("cyan", "magenta").multiline( 45 | `🎉 恭喜打包完成(总用时${dayjs 46 | .duration(endTime.diff(startTime)) 47 | .format("mm分ss秒")},打包后的大小为${size})` 48 | ), 49 | boxenOptions 50 | ) 51 | ); 52 | } 53 | }); 54 | } 55 | } 56 | }; 57 | } 58 | -------------------------------------------------------------------------------- /src/kubedoor-web/build/optimize.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * 此文件作用于 `vite.config.ts` 的 `optimizeDeps.include` 依赖预构建配置项 3 | * 依赖预构建,`vite` 启动时会将下面 include 里的模块,编译成 esm 格式并缓存到 node_modules/.vite 文件夹,页面加载到对应模块时如果浏览器有缓存就读取浏览器缓存,如果没有会读取本地缓存并按需加载 4 | * 尤其当您禁用浏览器缓存时(这种情况只应该发生在调试阶段)必须将对应模块加入到 include里,否则会遇到开发环境切换页面卡顿的问题(vite 会认为它是一个新的依赖包会重新加载并强制刷新页面),因为它既无法使用浏览器缓存,又没有在本地 node_modules/.vite 里缓存 5 | * 温馨提示:如果您使用的第三方库是全局引入,也就是引入到 src/main.ts 文件里,就不需要再添加到 include 里了,因为 vite 会自动将它们缓存到 node_modules/.vite 6 | */ 7 | const include = [ 8 | "qs", 9 | "mitt", 10 | "dayjs", 11 | "axios", 12 | "pinia", 13 | "vue-i18n", 14 | "vue-types", 15 | "js-cookie", 16 | "vue-tippy", 17 | "pinyin-pro", 18 | "sortablejs", 19 | "@vueuse/core", 20 | "@pureadmin/utils", 21 | "responsive-storage" 22 | ]; 23 | 24 | /** 25 | * 在预构建中强制排除的依赖项 26 | * 温馨提示:所有以 `@iconify-icons/` 开头引入的的本地图标模块,都应该加入到下面的 `exclude` 里,因为平台推荐的使用方式是哪里需要哪里引入而且都是单个的引入,不需要预构建,直接让浏览器加载就好 27 | */ 28 | const exclude = [ 29 | "@iconify-icons/ep", 30 | "@iconify-icons/ri", 31 | "@pureadmin/theme/dist/browser-utils" 32 | ]; 33 | 34 | export { include, exclude }; 35 | -------------------------------------------------------------------------------- /src/kubedoor-web/commitlint.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import("@commitlint/types").UserConfig} */ 4 | export default { 5 | ignores: [commit => commit.includes("init")], 6 | extends: ["@commitlint/config-conventional"], 7 | rules: { 8 | "body-leading-blank": [2, "always"], 9 | "footer-leading-blank": [1, "always"], 10 | "header-max-length": [2, "always", 108], 11 | "subject-empty": [2, "never"], 12 | "type-empty": [2, "never"], 13 | "type-enum": [ 14 | 2, 15 | "always", 16 | [ 17 | "feat", 18 | "fix", 19 | "perf", 20 | "style", 21 | "docs", 22 | "test", 23 | "refactor", 24 | "build", 25 | "ci", 26 | "chore", 27 | "revert", 28 | "wip", 29 | "workflow", 30 | "types", 31 | "release" 32 | ] 33 | ] 34 | } 35 | }; 36 | -------------------------------------------------------------------------------- /src/kubedoor-web/config: -------------------------------------------------------------------------------- 1 | type node -------------------------------------------------------------------------------- /src/kubedoor-web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 10 | 花折 - KubeDoor 11 | 12 | 15 | 16 | 17 | 18 |
19 | 83 |
84 |
85 | 86 | 87 | 88 | -------------------------------------------------------------------------------- /src/kubedoor-web/mock/asyncRoutes.ts: -------------------------------------------------------------------------------- 1 | // 模拟后端动态生成路由 2 | import { defineFakeRoute } from "vite-plugin-fake-server/client"; 3 | 4 | /** 5 | * roles:页面级别权限,这里模拟二种 "admin"、"common" 6 | * admin:管理员角色 7 | * common:普通角色 8 | */ 9 | const permissionRouter = { 10 | path: "/permission", 11 | meta: { 12 | title: "menus.purePermission", 13 | icon: "ep:lollipop", 14 | rank: 10 15 | }, 16 | children: [ 17 | { 18 | path: "/permission/page/index", 19 | name: "PermissionPage", 20 | meta: { 21 | title: "menus.purePermissionPage", 22 | roles: ["admin", "common"] 23 | } 24 | }, 25 | { 26 | path: "/permission/button", 27 | meta: { 28 | title: "menus.purePermissionButton", 29 | roles: ["admin", "common"] 30 | }, 31 | children: [ 32 | { 33 | path: "/permission/button/router", 34 | component: "permission/button/index", 35 | name: "PermissionButtonRouter", 36 | meta: { 37 | title: "menus.purePermissionButtonRouter", 38 | auths: [ 39 | "permission:btn:add", 40 | "permission:btn:edit", 41 | "permission:btn:delete" 42 | ] 43 | } 44 | }, 45 | { 46 | path: "/permission/button/login", 47 | component: "permission/button/perms", 48 | name: "PermissionButtonLogin", 49 | meta: { 50 | title: "menus.purePermissionButtonLogin" 51 | } 52 | } 53 | ] 54 | } 55 | ] 56 | }; 57 | 58 | export default defineFakeRoute([ 59 | { 60 | url: "/get-async-routes", 61 | method: "get", 62 | response: () => { 63 | return { 64 | success: true, 65 | data: [permissionRouter] 66 | }; 67 | } 68 | } 69 | ]); 70 | -------------------------------------------------------------------------------- /src/kubedoor-web/mock/login.ts: -------------------------------------------------------------------------------- 1 | // 根据角色动态生成路由 2 | import { defineFakeRoute } from "vite-plugin-fake-server/client"; 3 | 4 | export default defineFakeRoute([ 5 | { 6 | url: "/login", 7 | method: "post", 8 | response: ({ body }) => { 9 | if (body.username === "admin") { 10 | return { 11 | success: true, 12 | data: { 13 | avatar: "https://avatars.githubusercontent.com/u/44761321", 14 | username: "admin", 15 | nickname: "Admin", 16 | // 一个用户可能有多个角色 17 | roles: ["admin"], 18 | // 按钮级别权限 19 | permissions: ["*:*:*"], 20 | accessToken: "eyJhbGciOiJIUzUxMiJ9.admin", 21 | refreshToken: "eyJhbGciOiJIUzUxMiJ9.adminRefresh", 22 | expires: "2030/10/30 00:00:00" 23 | } 24 | }; 25 | } 26 | // else { 27 | // return { 28 | // success: true, 29 | // data: { 30 | // avatar: "https://avatars.githubusercontent.com/u/52823142", 31 | // username: "common", 32 | // nickname: "小林", 33 | // roles: ["common"], 34 | // permissions: ["permission:btn:add", "permission:btn:edit"], 35 | // accessToken: "eyJhbGciOiJIUzUxMiJ9.common", 36 | // refreshToken: "eyJhbGciOiJIUzUxMiJ9.commonRefresh", 37 | // expires: "2030/10/30 00:00:00" 38 | // } 39 | // }; 40 | // } 41 | } 42 | } 43 | ]); 44 | -------------------------------------------------------------------------------- /src/kubedoor-web/mock/refreshToken.ts: -------------------------------------------------------------------------------- 1 | import { defineFakeRoute } from "vite-plugin-fake-server/client"; 2 | 3 | // 模拟刷新token接口 4 | export default defineFakeRoute([ 5 | { 6 | url: "/refresh-token", 7 | method: "post", 8 | response: ({ body }) => { 9 | if (body.refreshToken) { 10 | return { 11 | success: true, 12 | data: { 13 | accessToken: "eyJhbGciOiJIUzUxMiJ9.newAdmin", 14 | refreshToken: "eyJhbGciOiJIUzUxMiJ9.newAdminRefresh", 15 | // `expires`选择这种日期格式是为了方便调试,后端直接设置时间戳或许更方便(每次都应该递增)。如果后端返回的是时间戳格式,前端开发请来到这个目录`src/utils/auth.ts`,把第`38`行的代码换成expires = data.expires即可。 16 | expires: "2030/10/30 23:59:59" 17 | } 18 | }; 19 | } else { 20 | return { 21 | success: false, 22 | data: {} 23 | }; 24 | } 25 | } 26 | } 27 | ]); 28 | -------------------------------------------------------------------------------- /src/kubedoor-web/postcss.config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | 3 | /** @type {import('postcss-load-config').Config} */ 4 | export default { 5 | plugins: { 6 | "postcss-import": {}, 7 | "tailwindcss/nesting": {}, 8 | tailwindcss: {}, 9 | autoprefixer: {}, 10 | ...(process.env.NODE_ENV === "production" ? { cssnano: {} } : {}) 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/kubedoor-web/public/18logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/public/18logo.png -------------------------------------------------------------------------------- /src/kubedoor-web/public/18logo1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/public/18logo1.png -------------------------------------------------------------------------------- /src/kubedoor-web/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/public/favicon.ico -------------------------------------------------------------------------------- /src/kubedoor-web/public/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/public/platform-config.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "5.8.0", 3 | "Title": "花折 - KubeDoor", 4 | "FixedHeader": true, 5 | "HiddenSideBar": false, 6 | "MultiTagsCache": false, 7 | "KeepAlive": true, 8 | "Layout": "vertical", 9 | "Theme": "light", 10 | "DarkMode": false, 11 | "OverallStyle": "light", 12 | "Grey": false, 13 | "Weak": false, 14 | "HideTabs": true, 15 | "HideFooter": true, 16 | "Stretch": false, 17 | "SidebarStatus": false, 18 | "EpThemeColor": "#409EFF", 19 | "ShowLogo": true, 20 | "ShowModel": "smart", 21 | "MenuArrowIconNoTransition": false, 22 | "CachingAsyncRoutes": false, 23 | "TooltipEffect": "light", 24 | "ResponsiveStorageNameSpace": "responsive-", 25 | "MenuSearchHistory": 6 26 | } -------------------------------------------------------------------------------- /src/kubedoor-web/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 28 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/api/monit.ts: -------------------------------------------------------------------------------- 1 | import { http } from "@/utils/http"; 2 | 3 | type ResultTable = { 4 | success: boolean; 5 | data?: Array; 6 | meta?: Array; 7 | pods?: Array; 8 | count: any; 9 | }; 10 | 11 | /** 12 | * 获取K8S环境列表 13 | */ 14 | export const getPromEnv = () => { 15 | return http.request("get", "/api/prom_env"); 16 | }; 17 | 18 | /** 19 | * 获取命名空间列表 20 | * @param env K8S环境 21 | */ 22 | export const getPromNamespace = (env: string) => { 23 | return http.request("get", "/api/prom_ns", { 24 | params: { env } 25 | }); 26 | }; 27 | 28 | /** 29 | * 获取监控数据 30 | * @param env K8S环境 31 | * @param ns 命名空间(可选) 32 | */ 33 | export const getPromQueryData = (env: string, ns?: string) => { 34 | const params: Record = { env }; 35 | if (ns) { 36 | params.ns = ns; 37 | } 38 | return http.request("get", "/api/prom_query", { 39 | params 40 | }); 41 | }; 42 | 43 | /** 44 | * 获取Pod数据 45 | * @param env K8S环境 46 | * @param namespace 命名空间 47 | * @param deployment 部署名称 48 | */ 49 | export const getPodData = ( 50 | env: string, 51 | namespace: string, 52 | deployment: string 53 | ) => { 54 | return http.request("get", "/api/get_dpm_pods", { 55 | params: { env, namespace, deployment } 56 | }); 57 | }; 58 | 59 | export const updatePodCount = (data?: any) => { 60 | return http.request("post", "/api/sql", { 61 | params: { 62 | add_http_cors_header: 1, 63 | default_format: "JSONCompact" 64 | }, 65 | data: `ALTER TABLE __KUBEDOORDB__.k8s_res_control UPDATE pod_count_manual=${data.pod_count_manual} WHERE env = '${data.env}' AND namespace='${data.namespace}' AND deployment='${data.deployment_name}' `, 66 | headers: { 67 | "Content-Type": "text/plain;charset=UTF-8" 68 | } 69 | }); 70 | }; 71 | // 获取是否显示"已开启固定节点均衡模式" 72 | export const showAddLabel = (env: string, namespace: string) => { 73 | return http.request("post", "/api/sql", { 74 | params: { 75 | add_http_cors_header: 1, 76 | default_format: "JSONCompact" 77 | }, 78 | data: `SELECT 1 FROM __KUBEDOORDB__.k8s_agent_status where env = '${env}' and admission = 1 and scheduler = 1 and admission_namespace like '%"${namespace}"%' `, 79 | headers: { 80 | "Content-Type": "text/plain;charset=UTF-8" 81 | } 82 | }); 83 | }; 84 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/api/routes.ts: -------------------------------------------------------------------------------- 1 | import { http } from "@/utils/http"; 2 | 3 | type Result = { 4 | success: boolean; 5 | data: Array; 6 | }; 7 | 8 | export const getAsyncRoutes = () => { 9 | return http.request("get", "/get-async-routes"); 10 | }; 11 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/api/user.ts: -------------------------------------------------------------------------------- 1 | import { http } from "@/utils/http"; 2 | 3 | export type UserResult = { 4 | success: boolean; 5 | data: { 6 | /** 头像 */ 7 | avatar: string; 8 | /** 用户名 */ 9 | username: string; 10 | /** 昵称 */ 11 | nickname: string; 12 | /** 当前登录用户的角色 */ 13 | roles: Array; 14 | /** 按钮级别权限 */ 15 | permissions: Array; 16 | /** `token` */ 17 | accessToken: string; 18 | /** 用于调用刷新`accessToken`的接口时所需的`token` */ 19 | refreshToken: string; 20 | /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */ 21 | expires: Date; 22 | }; 23 | }; 24 | 25 | export type RefreshTokenResult = { 26 | success: boolean; 27 | data: { 28 | /** `token` */ 29 | accessToken: string; 30 | /** 用于调用刷新`accessToken`的接口时所需的`token` */ 31 | refreshToken: string; 32 | /** `accessToken`的过期时间(格式'xxxx/xx/xx xx:xx:xx') */ 33 | expires: Date; 34 | }; 35 | }; 36 | 37 | /** 登录 */ 38 | export const getLogin = (data?: object) => { 39 | return http.request("post", "/login", { data }); 40 | }; 41 | 42 | /** 刷新`token` */ 43 | export const refreshTokenApi = (data?: object) => { 44 | return http.request("post", "/refresh-token", { data }); 45 | }; 46 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/iconfont/iconfont.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: "iconfont"; /* Project id 2208059 */ 3 | src: 4 | url("iconfont.woff2?t=1671895108120") format("woff2"), 5 | url("iconfont.woff?t=1671895108120") format("woff"), 6 | url("iconfont.ttf?t=1671895108120") format("truetype"); 7 | } 8 | 9 | .iconfont { 10 | font-family: "iconfont" !important; 11 | font-size: 16px; 12 | font-style: normal; 13 | -webkit-font-smoothing: antialiased; 14 | -moz-osx-font-smoothing: grayscale; 15 | } 16 | 17 | .pure-iconfont-tabs:before { 18 | content: "\e63e"; 19 | } 20 | 21 | .pure-iconfont-logo:before { 22 | content: "\e620"; 23 | } 24 | 25 | .pure-iconfont-new:before { 26 | content: "\e615"; 27 | } 28 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/iconfont/iconfont.json: -------------------------------------------------------------------------------- 1 | { 2 | "id": "2208059", 3 | "name": "pure-admin", 4 | "font_family": "iconfont", 5 | "css_prefix_text": "pure-iconfont-", 6 | "description": "pure-admin-iconfont", 7 | "glyphs": [ 8 | { 9 | "icon_id": "20594647", 10 | "name": "Tabs", 11 | "font_class": "tabs", 12 | "unicode": "e63e", 13 | "unicode_decimal": 58942 14 | }, 15 | { 16 | "icon_id": "22129506", 17 | "name": "PureLogo", 18 | "font_class": "logo", 19 | "unicode": "e620", 20 | "unicode_decimal": 58912 21 | }, 22 | { 23 | "icon_id": "7795615", 24 | "name": "New", 25 | "font_class": "new", 26 | "unicode": "e615", 27 | "unicode_decimal": 58901 28 | } 29 | ] 30 | } 31 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/iconfont/iconfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/src/assets/iconfont/iconfont.ttf -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/iconfont/iconfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/src/assets/iconfont/iconfont.woff -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/iconfont/iconfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/src/assets/iconfont/iconfont.woff2 -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/login/avatar.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/login/bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/src/assets/login/bg.png -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/back_top.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/day.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/enter_outlined.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/exit_screen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/full_screen.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/globalization.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/keyboard_esc.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/svg/system.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/table-bar/collapse.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/table-bar/drag.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/table-bar/expand.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/table-bar/refresh.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/table-bar/settings.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/assets/user.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CassInfra/KubeDoor/81145a0aab5cfc8d3818eebb897ba6b500a4a707/src/kubedoor-web/src/assets/user.jpg -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReAuth/index.ts: -------------------------------------------------------------------------------- 1 | import auth from "./src/auth"; 2 | 3 | const Auth = auth; 4 | 5 | export { Auth }; 6 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReAuth/src/auth.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, Fragment } from "vue"; 2 | import { hasAuth } from "@/router/utils"; 3 | 4 | export default defineComponent({ 5 | name: "Auth", 6 | props: { 7 | value: { 8 | type: undefined, 9 | default: [] 10 | } 11 | }, 12 | setup(props, { slots }) { 13 | return () => { 14 | if (!slots) return null; 15 | return hasAuth(props.value) ? ( 16 | {slots.default?.()} 17 | ) : null; 18 | }; 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReCol/index.ts: -------------------------------------------------------------------------------- 1 | import { ElCol } from "element-plus"; 2 | import { h, defineComponent } from "vue"; 3 | 4 | // 封装element-plus的el-col组件 5 | export default defineComponent({ 6 | name: "ReCol", 7 | props: { 8 | value: { 9 | type: Number, 10 | default: 24 11 | } 12 | }, 13 | render() { 14 | const attrs = this.$attrs; 15 | const val = this.value; 16 | return h( 17 | ElCol, 18 | { 19 | xs: val, 20 | sm: val, 21 | md: val, 22 | lg: val, 23 | xl: val, 24 | ...attrs 25 | }, 26 | { default: () => this.$slots.default() } 27 | ); 28 | } 29 | }); 30 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReDialog/index.ts: -------------------------------------------------------------------------------- 1 | import { ref } from "vue"; 2 | import reDialog from "./index.vue"; 3 | import { useTimeoutFn } from "@vueuse/core"; 4 | import { withInstall } from "@pureadmin/utils"; 5 | import type { 6 | EventType, 7 | ArgsType, 8 | DialogProps, 9 | ButtonProps, 10 | DialogOptions 11 | } from "./type"; 12 | 13 | const dialogStore = ref>([]); 14 | 15 | /** 打开弹框 */ 16 | const addDialog = (options: DialogOptions) => { 17 | const open = () => 18 | dialogStore.value.push(Object.assign(options, { visible: true })); 19 | if (options?.openDelay) { 20 | useTimeoutFn(() => { 21 | open(); 22 | }, options.openDelay); 23 | } else { 24 | open(); 25 | } 26 | }; 27 | 28 | /** 关闭弹框 */ 29 | const closeDialog = (options: DialogOptions, index: number, args?: any) => { 30 | dialogStore.value[index].visible = false; 31 | options.closeCallBack && options.closeCallBack({ options, index, args }); 32 | 33 | const closeDelay = options?.closeDelay ?? 200; 34 | useTimeoutFn(() => { 35 | dialogStore.value.splice(index, 1); 36 | }, closeDelay); 37 | }; 38 | 39 | /** 40 | * @description 更改弹框自身属性值 41 | * @param value 属性值 42 | * @param key 属性,默认`title` 43 | * @param index 弹框索引(默认`0`,代表只有一个弹框,对于嵌套弹框要改哪个弹框的属性值就把该弹框索引赋给`index`) 44 | */ 45 | const updateDialog = (value: any, key = "title", index = 0) => { 46 | dialogStore.value[index][key] = value; 47 | }; 48 | 49 | /** 关闭所有弹框 */ 50 | const closeAllDialog = () => { 51 | dialogStore.value = []; 52 | }; 53 | 54 | /** 千万别忘了在下面这三处引入并注册下,放心注册,不使用`addDialog`调用就不会被挂载 55 | * https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L4 56 | * https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L12 57 | * https://github.com/pure-admin/vue-pure-admin/blob/main/src/App.vue#L22 58 | */ 59 | const ReDialog = withInstall(reDialog); 60 | 61 | export type { EventType, ArgsType, DialogProps, ButtonProps, DialogOptions }; 62 | export { 63 | ReDialog, 64 | dialogStore, 65 | addDialog, 66 | closeDialog, 67 | updateDialog, 68 | closeAllDialog 69 | }; 70 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/index.ts: -------------------------------------------------------------------------------- 1 | import iconifyIconOffline from "./src/iconifyIconOffline"; 2 | import iconifyIconOnline from "./src/iconifyIconOnline"; 3 | import fontIcon from "./src/iconfont"; 4 | 5 | /** 本地图标组件 */ 6 | const IconifyIconOffline = iconifyIconOffline; 7 | /** 在线图标组件 */ 8 | const IconifyIconOnline = iconifyIconOnline; 9 | /** `iconfont`组件 */ 10 | const FontIcon = fontIcon; 11 | 12 | export { IconifyIconOffline, IconifyIconOnline, FontIcon }; 13 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/src/hooks.ts: -------------------------------------------------------------------------------- 1 | import type { iconType } from "./types"; 2 | import { h, defineComponent, type Component } from "vue"; 3 | import { IconifyIconOnline, IconifyIconOffline, FontIcon } from "../index"; 4 | 5 | /** 6 | * 支持 `iconfont`、自定义 `svg` 以及 `iconify` 中所有的图标 7 | * @see 点击查看文档图标篇 {@link https://pure-admin.github.io/pure-admin-doc/pages/icon/} 8 | * @param icon 必传 图标 9 | * @param attrs 可选 iconType 属性 10 | * @returns Component 11 | */ 12 | export function useRenderIcon(icon: any, attrs?: iconType): Component { 13 | // iconfont 14 | const ifReg = /^IF-/; 15 | // typeof icon === "function" 属于SVG 16 | if (ifReg.test(icon)) { 17 | // iconfont 18 | const name = icon.split(ifReg)[1]; 19 | const iconName = name.slice( 20 | 0, 21 | name.indexOf(" ") == -1 ? name.length : name.indexOf(" ") 22 | ); 23 | const iconType = name.slice(name.indexOf(" ") + 1, name.length); 24 | return defineComponent({ 25 | name: "FontIcon", 26 | render() { 27 | return h(FontIcon, { 28 | icon: iconName, 29 | iconType, 30 | ...attrs 31 | }); 32 | } 33 | }); 34 | } else if (typeof icon === "function" || typeof icon?.render === "function") { 35 | // svg 36 | return attrs ? h(icon, { ...attrs }) : icon; 37 | } else if (typeof icon === "object") { 38 | return defineComponent({ 39 | name: "OfflineIcon", 40 | render() { 41 | return h(IconifyIconOffline, { 42 | icon: icon, 43 | ...attrs 44 | }); 45 | } 46 | }); 47 | } else { 48 | // 通过是否存在 : 符号来判断是在线还是本地图标,存在即是在线图标,反之 49 | return defineComponent({ 50 | name: "Icon", 51 | render() { 52 | const IconifyIcon = 53 | icon && icon.includes(":") ? IconifyIconOnline : IconifyIconOffline; 54 | return h(IconifyIcon, { 55 | icon: icon, 56 | ...attrs 57 | }); 58 | } 59 | }); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/src/iconfont.ts: -------------------------------------------------------------------------------- 1 | import { h, defineComponent } from "vue"; 2 | 3 | // 封装iconfont组件,默认`font-class`引用模式,支持`unicode`引用、`font-class`引用、`symbol`引用 (https://www.iconfont.cn/help/detail?spm=a313x.7781069.1998910419.20&helptype=code) 4 | export default defineComponent({ 5 | name: "FontIcon", 6 | props: { 7 | icon: { 8 | type: String, 9 | default: "" 10 | } 11 | }, 12 | render() { 13 | const attrs = this.$attrs; 14 | if (Object.keys(attrs).includes("uni") || attrs?.iconType === "uni") { 15 | return h( 16 | "i", 17 | { 18 | class: "iconfont", 19 | ...attrs 20 | }, 21 | this.icon 22 | ); 23 | } else if ( 24 | Object.keys(attrs).includes("svg") || 25 | attrs?.iconType === "svg" 26 | ) { 27 | return h( 28 | "svg", 29 | { 30 | class: "icon-svg", 31 | "aria-hidden": true 32 | }, 33 | { 34 | default: () => [ 35 | h("use", { 36 | "xlink:href": `#${this.icon}` 37 | }) 38 | ] 39 | } 40 | ); 41 | } else { 42 | return h("i", { 43 | class: `iconfont ${this.icon}`, 44 | ...attrs 45 | }); 46 | } 47 | } 48 | }); 49 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/src/iconifyIconOffline.ts: -------------------------------------------------------------------------------- 1 | import { h, defineComponent } from "vue"; 2 | import { Icon as IconifyIcon, addIcon } from "@iconify/vue/dist/offline"; 3 | 4 | // Iconify Icon在Vue里本地使用(用于内网环境) 5 | export default defineComponent({ 6 | name: "IconifyIconOffline", 7 | components: { IconifyIcon }, 8 | props: { 9 | icon: { 10 | default: null 11 | } 12 | }, 13 | render() { 14 | if (typeof this.icon === "object") addIcon(this.icon, this.icon); 15 | const attrs = this.$attrs; 16 | return h( 17 | IconifyIcon, 18 | { 19 | icon: this.icon, 20 | style: attrs?.style 21 | ? Object.assign(attrs.style, { outline: "none" }) 22 | : { outline: "none" }, 23 | ...attrs 24 | }, 25 | { 26 | default: () => [] 27 | } 28 | ); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/src/iconifyIconOnline.ts: -------------------------------------------------------------------------------- 1 | import { h, defineComponent } from "vue"; 2 | import { Icon as IconifyIcon } from "@iconify/vue"; 3 | 4 | // Iconify Icon在Vue里在线使用(用于外网环境) 5 | export default defineComponent({ 6 | name: "IconifyIconOnline", 7 | components: { IconifyIcon }, 8 | props: { 9 | icon: { 10 | type: String, 11 | default: "" 12 | } 13 | }, 14 | render() { 15 | const attrs = this.$attrs; 16 | return h( 17 | IconifyIcon, 18 | { 19 | icon: `${this.icon}`, 20 | style: attrs?.style 21 | ? Object.assign(attrs.style, { outline: "none" }) 22 | : { outline: "none" }, 23 | ...attrs 24 | }, 25 | { 26 | default: () => [] 27 | } 28 | ); 29 | } 30 | }); 31 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/src/offlineIcon.ts: -------------------------------------------------------------------------------- 1 | // 这里存放本地图标,在 src/layout/index.vue 文件中加载,避免在首启动加载 2 | import { addIcon } from "@iconify/vue/dist/offline"; 3 | 4 | // 本地菜单图标,后端在路由的 icon 中返回对应的图标字符串并且前端在此处使用 addIcon 添加即可渲染菜单图标 5 | // @iconify-icons/ep 6 | import Lollipop from "@iconify-icons/ep/lollipop"; 7 | import HomeFilled from "@iconify-icons/ep/home-filled"; 8 | addIcon("ep:lollipop", Lollipop); 9 | addIcon("ep:home-filled", HomeFilled); 10 | // @iconify-icons/ri 11 | import Search from "@iconify-icons/ri/search-line"; 12 | import InformationLine from "@iconify-icons/ri/information-line"; 13 | addIcon("ri:search-line", Search); 14 | addIcon("ri:information-line", InformationLine); 15 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReIcon/src/types.ts: -------------------------------------------------------------------------------- 1 | export interface iconType { 2 | // iconify (https://docs.iconify.design/icon-components/vue/#properties) 3 | inline?: boolean; 4 | width?: string | number; 5 | height?: string | number; 6 | horizontalFlip?: boolean; 7 | verticalFlip?: boolean; 8 | flip?: string; 9 | rotate?: number | string; 10 | color?: string; 11 | horizontalAlign?: boolean; 12 | verticalAlign?: boolean; 13 | align?: string; 14 | onLoad?: Function; 15 | includes?: Function; 16 | // svg 需要什么SVG属性自行添加 17 | fill?: string; 18 | // all icon 19 | style?: object; 20 | } 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/RePerms/index.ts: -------------------------------------------------------------------------------- 1 | import perms from "./src/perms"; 2 | 3 | const Perms = perms; 4 | 5 | export { Perms }; 6 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/RePerms/src/perms.tsx: -------------------------------------------------------------------------------- 1 | import { defineComponent, Fragment } from "vue"; 2 | import { hasPerms } from "@/utils/auth"; 3 | 4 | export default defineComponent({ 5 | name: "Perms", 6 | props: { 7 | value: { 8 | type: undefined, 9 | default: [] 10 | } 11 | }, 12 | setup(props, { slots }) { 13 | return () => { 14 | if (!slots) return null; 15 | return hasPerms(props.value) ? ( 16 | {slots.default?.()} 17 | ) : null; 18 | }; 19 | } 20 | }); 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/RePureTableBar/index.ts: -------------------------------------------------------------------------------- 1 | import pureTableBar from "./src/bar"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 配合 `@pureadmin/table` 实现快速便捷的表格操作 https://github.com/pure-admin/pure-admin-table */ 5 | export const PureTableBar = withInstall(pureTableBar); 6 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReSegmented/index.ts: -------------------------------------------------------------------------------- 1 | import reSegmented from "./src/index"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 分段控制器组件 */ 5 | export const ReSegmented = withInstall(reSegmented); 6 | 7 | export default ReSegmented; 8 | export type { OptionsType } from "./src/type"; 9 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReSegmented/src/type.ts: -------------------------------------------------------------------------------- 1 | import type { VNode, Component } from "vue"; 2 | import type { iconType } from "@/components/ReIcon/src/types.ts"; 3 | 4 | export interface OptionsType { 5 | /** 文字 */ 6 | label?: string | (() => VNode | Component); 7 | /** 8 | * @description 图标,采用平台内置的 `useRenderIcon` 函数渲染 9 | * @see {@link 用法参考 https://pure-admin.github.io/pure-admin-doc/pages/icon/#%E9%80%9A%E7%94%A8%E5%9B%BE%E6%A0%87-userendericon-hooks } 10 | */ 11 | icon?: string | Component; 12 | /** 图标属性、样式配置 */ 13 | iconAttrs?: iconType; 14 | /** 值 */ 15 | value?: any; 16 | /** 是否禁用 */ 17 | disabled?: boolean; 18 | /** `tooltip` 提示 */ 19 | tip?: string; 20 | } 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReText/index.ts: -------------------------------------------------------------------------------- 1 | import reText from "./src/index.vue"; 2 | import { withInstall } from "@pureadmin/utils"; 3 | 4 | /** 支持`Tooltip`提示的文本省略组件 */ 5 | export const ReText = withInstall(reText); 6 | 7 | export default ReText; 8 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/components/ReText/src/index.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 67 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/config/index.ts: -------------------------------------------------------------------------------- 1 | import axios from "axios"; 2 | import type { App } from "vue"; 3 | 4 | let config: object = {}; 5 | const { VITE_PUBLIC_PATH } = import.meta.env; 6 | 7 | const setConfig = (cfg?: unknown) => { 8 | config = Object.assign(config, cfg); 9 | }; 10 | 11 | const getConfig = (key?: string): PlatformConfigs => { 12 | if (typeof key === "string") { 13 | const arr = key.split("."); 14 | if (arr && arr.length) { 15 | let data = config; 16 | arr.forEach(v => { 17 | if (data && typeof data[v] !== "undefined") { 18 | data = data[v]; 19 | } else { 20 | data = null; 21 | } 22 | }); 23 | return data; 24 | } 25 | } 26 | return config; 27 | }; 28 | 29 | /** 获取项目动态全局配置 */ 30 | export const getPlatformConfig = async (app: App): Promise => { 31 | app.config.globalProperties.$config = getConfig(); 32 | return axios({ 33 | method: "get", 34 | url: `${VITE_PUBLIC_PATH}platform-config.json` 35 | }) 36 | .then(({ data: config }) => { 37 | let $config = app.config.globalProperties.$config; 38 | // 自动注入系统配置 39 | if (app && $config && typeof config === "object") { 40 | $config = Object.assign($config, config); 41 | app.config.globalProperties.$config = $config; 42 | // 设置全局配置 43 | setConfig($config); 44 | } 45 | return $config; 46 | }) 47 | .catch(() => { 48 | throw "请在public文件夹下添加platform-config.json配置文件"; 49 | }); 50 | }; 51 | 52 | /** 本地响应式存储的命名空间 */ 53 | const responsiveStorageNameSpace = () => getConfig().ResponsiveStorageNameSpace; 54 | 55 | export { getConfig, setConfig, responsiveStorageNameSpace }; 56 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/auth/index.ts: -------------------------------------------------------------------------------- 1 | import { hasAuth } from "@/router/utils"; 2 | import type { Directive, DirectiveBinding } from "vue"; 3 | 4 | export const auth: Directive = { 5 | mounted(el: HTMLElement, binding: DirectiveBinding>) { 6 | const { value } = binding; 7 | if (value) { 8 | !hasAuth(value) && el.parentNode?.removeChild(el); 9 | } else { 10 | throw new Error( 11 | "[Directive: auth]: need auths! Like v-auth=\"['btn.add','btn.edit']\"" 12 | ); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/copy/index.ts: -------------------------------------------------------------------------------- 1 | import { message } from "@/utils/message"; 2 | import { useEventListener } from "@vueuse/core"; 3 | import { copyTextToClipboard } from "@pureadmin/utils"; 4 | import type { Directive, DirectiveBinding } from "vue"; 5 | 6 | export interface CopyEl extends HTMLElement { 7 | copyValue: string; 8 | } 9 | 10 | /** 文本复制指令(默认双击复制) */ 11 | export const copy: Directive = { 12 | mounted(el: CopyEl, binding: DirectiveBinding) { 13 | const { value } = binding; 14 | if (value) { 15 | el.copyValue = value; 16 | const arg = binding.arg ?? "dblclick"; 17 | // Register using addEventListener on mounted, and removeEventListener automatically on unmounted 18 | useEventListener(el, arg, () => { 19 | const success = copyTextToClipboard(el.copyValue); 20 | success 21 | ? message("复制成功", { type: "success" }) 22 | : message("复制失败", { type: "error" }); 23 | }); 24 | } else { 25 | throw new Error( 26 | '[Directive: copy]: need value! Like v-copy="modelValue"' 27 | ); 28 | } 29 | }, 30 | updated(el: CopyEl, binding: DirectiveBinding) { 31 | el.copyValue = binding.value; 32 | } 33 | }; 34 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./auth"; 2 | export * from "./copy"; 3 | export * from "./longpress"; 4 | export * from "./optimize"; 5 | export * from "./perms"; 6 | export * from "./ripple"; 7 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/longpress/index.ts: -------------------------------------------------------------------------------- 1 | import { useEventListener } from "@vueuse/core"; 2 | import type { Directive, DirectiveBinding } from "vue"; 3 | import { subBefore, subAfter, isFunction } from "@pureadmin/utils"; 4 | 5 | export const longpress: Directive = { 6 | mounted(el: HTMLElement, binding: DirectiveBinding) { 7 | const cb = binding.value; 8 | if (cb && isFunction(cb)) { 9 | let timer = null; 10 | let interTimer = null; 11 | let num = 500; 12 | let interNum = null; 13 | const isInter = binding?.arg?.includes(":") ?? false; 14 | 15 | if (isInter) { 16 | num = Number(subBefore(binding.arg, ":")); 17 | interNum = Number(subAfter(binding.arg, ":")); 18 | } else if (binding.arg) { 19 | num = Number(binding.arg); 20 | } 21 | 22 | const clear = () => { 23 | if (timer) { 24 | clearTimeout(timer); 25 | timer = null; 26 | } 27 | if (interTimer) { 28 | clearInterval(interTimer); 29 | interTimer = null; 30 | } 31 | }; 32 | 33 | const onDownInter = (ev: PointerEvent) => { 34 | ev.preventDefault(); 35 | if (interTimer === null) { 36 | interTimer = setInterval(() => cb(), interNum); 37 | } 38 | }; 39 | 40 | const onDown = (ev: PointerEvent) => { 41 | clear(); 42 | ev.preventDefault(); 43 | if (timer === null) { 44 | timer = isInter 45 | ? setTimeout(() => { 46 | cb(); 47 | onDownInter(ev); 48 | }, num) 49 | : setTimeout(() => cb(), num); 50 | } 51 | }; 52 | 53 | // Register using addEventListener on mounted, and removeEventListener automatically on unmounted 54 | useEventListener(el, "pointerdown", onDown); 55 | useEventListener(el, "pointerup", clear); 56 | useEventListener(el, "pointerleave", clear); 57 | } else { 58 | throw new Error( 59 | '[Directive: longpress]: need callback and callback must be a function! Like v-longpress="callback"' 60 | ); 61 | } 62 | } 63 | }; 64 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/optimize/index.ts: -------------------------------------------------------------------------------- 1 | import { 2 | isArray, 3 | throttle, 4 | debounce, 5 | isObject, 6 | isFunction 7 | } from "@pureadmin/utils"; 8 | import { useEventListener } from "@vueuse/core"; 9 | import type { Directive, DirectiveBinding } from "vue"; 10 | 11 | export interface OptimizeOptions { 12 | /** 事件名 */ 13 | event: string; 14 | /** 事件触发的方法 */ 15 | fn: (...params: any) => any; 16 | /** 是否立即执行 */ 17 | immediate?: boolean; 18 | /** 防抖或节流的延迟时间(防抖默认:`200`毫秒、节流默认:`1000`毫秒) */ 19 | timeout?: number; 20 | /** 传递的参数 */ 21 | params?: any; 22 | } 23 | 24 | /** 防抖(v-optimize或v-optimize:debounce)、节流(v-optimize:throttle)指令 */ 25 | export const optimize: Directive = { 26 | mounted(el: HTMLElement, binding: DirectiveBinding) { 27 | const { value } = binding; 28 | const optimizeType = binding.arg ?? "debounce"; 29 | const type = ["debounce", "throttle"].find(t => t === optimizeType); 30 | if (type) { 31 | if (value && value.event && isFunction(value.fn)) { 32 | let params = value?.params; 33 | if (params) { 34 | if (isArray(params) || isObject(params)) { 35 | params = isObject(params) ? Array.of(params) : params; 36 | } else { 37 | throw new Error( 38 | "[Directive: optimize]: `params` must be an array or object" 39 | ); 40 | } 41 | } 42 | // Register using addEventListener on mounted, and removeEventListener automatically on unmounted 43 | useEventListener( 44 | el, 45 | value.event, 46 | type === "debounce" 47 | ? debounce( 48 | params ? () => value.fn(...params) : value.fn, 49 | value?.timeout ?? 200, 50 | value?.immediate ?? false 51 | ) 52 | : throttle( 53 | params ? () => value.fn(...params) : value.fn, 54 | value?.timeout ?? 1000 55 | ) 56 | ); 57 | } else { 58 | throw new Error( 59 | "[Directive: optimize]: `event` and `fn` are required, and `fn` must be a function" 60 | ); 61 | } 62 | } else { 63 | throw new Error( 64 | "[Directive: optimize]: only `debounce` and `throttle` are supported" 65 | ); 66 | } 67 | } 68 | }; 69 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/perms/index.ts: -------------------------------------------------------------------------------- 1 | import { hasPerms } from "@/utils/auth"; 2 | import type { Directive, DirectiveBinding } from "vue"; 3 | 4 | export const perms: Directive = { 5 | mounted(el: HTMLElement, binding: DirectiveBinding>) { 6 | const { value } = binding; 7 | if (value) { 8 | !hasPerms(value) && el.parentNode?.removeChild(el); 9 | } else { 10 | throw new Error( 11 | "[Directive: perms]: need perms! Like v-perms=\"['btn.add','btn.edit']\"" 12 | ); 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/directives/ripple/index.scss: -------------------------------------------------------------------------------- 1 | /* stylelint-disable-next-line scss/dollar-variable-colon-space-after */ 2 | $ripple-animation-transition-in: 3 | transform 0.4s cubic-bezier(0, 0, 0.2, 1), 4 | opacity 0.2s cubic-bezier(0, 0, 0.2, 1) !default; 5 | $ripple-animation-transition-out: opacity 0.5s cubic-bezier(0, 0, 0.2, 1) !default; 6 | $ripple-animation-visible-opacity: 0.25 !default; 7 | 8 | .v-ripple { 9 | &__container { 10 | position: absolute; 11 | top: 0; 12 | left: 0; 13 | z-index: 0; 14 | width: 100%; 15 | height: 100%; 16 | overflow: hidden; 17 | pointer-events: none; 18 | border-radius: inherit; 19 | contain: strict; 20 | } 21 | 22 | &__animation { 23 | position: absolute; 24 | top: 0; 25 | left: 0; 26 | overflow: hidden; 27 | pointer-events: none; 28 | background: currentcolor; 29 | border-radius: 50%; 30 | opacity: 0; 31 | will-change: transform, opacity; 32 | 33 | &--enter { 34 | opacity: 0; 35 | transition: none; 36 | } 37 | 38 | &--in { 39 | opacity: $ripple-animation-visible-opacity; 40 | transition: $ripple-animation-transition-in; 41 | } 42 | 43 | &--out { 44 | opacity: 0; 45 | transition: $ripple-animation-transition-out; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-footer/index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 21 | 22 | 32 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-notice/components/NoticeList.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 25 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-search/components/SearchFooter.vue: -------------------------------------------------------------------------------- 1 | 16 | 17 | 37 | 38 | 64 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-search/components/SearchHistoryItem.vue: -------------------------------------------------------------------------------- 1 | 28 | 29 | 46 | 47 | 54 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-search/index.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 22 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-search/types.ts: -------------------------------------------------------------------------------- 1 | interface optionsItem { 2 | path: string; 3 | type: "history" | "collect"; 4 | meta: { 5 | icon?: string; 6 | title?: string; 7 | }; 8 | } 9 | 10 | interface dragItem { 11 | oldIndex: number; 12 | newIndex: number; 13 | } 14 | 15 | interface Props { 16 | value: string; 17 | options: Array; 18 | } 19 | 20 | export type { optionsItem, dragItem, Props }; 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarCenterCollapse.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 56 | 57 | 75 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarExtraIcon.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 21 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarFullScreen.vue: -------------------------------------------------------------------------------- 1 | 25 | 26 | 31 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarLeftCollapse.vue: -------------------------------------------------------------------------------- 1 | 44 | 45 | 63 | 64 | 74 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarLinkItem.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 33 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarLogo.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 38 | 39 | 73 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-sidebar/components/SidebarTopCollapse.vue: -------------------------------------------------------------------------------- 1 | 24 | 25 | 39 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/components/lay-tag/components/TagChrome.vue: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /src/kubedoor-web/src/layout/frame.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 |