├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .idea
├── .gitignore
├── kubemanage.iml
├── modules.xml
└── vcs.xml
├── LICENSE
├── README.md
├── README_en.md
├── cmd
├── app
│ ├── config
│ │ ├── config.go
│ │ └── viper.go
│ ├── options
│ │ └── options.go
│ └── server.go
└── main.go
├── config.yaml
├── controller
├── api
│ ├── api.go
│ └── api_router.go
├── authority
│ ├── authority.go
│ ├── authority_router.go
│ └── casbin.go
├── kubeController
│ ├── configmap.go
│ ├── daemonset.go
│ ├── deployment.go
│ ├── ingress.go
│ ├── kubeRouter.go
│ ├── namespace.go
│ ├── node.go
│ ├── persistentVolumeClaim.go
│ ├── persistentvolume.go
│ ├── pod.go
│ ├── secret.go
│ ├── service.go
│ ├── statefulset.go
│ └── workflow.go
├── menu
│ ├── menu.go
│ └── menu_router.go
├── operation
│ ├── operation.go
│ └── operation_router.go
├── other
│ └── swagger.go
└── user
│ ├── user.go
│ └── user_router.go
├── dao
├── api
│ └── api.go
├── authority
│ ├── authority.go
│ └── sys_authority_menus.go
├── factory.go
├── menu
│ └── basemenu.go
├── model
│ ├── authorities_menus.go
│ ├── authority.go
│ ├── casbin.go
│ ├── common.go
│ ├── db_initializer.go
│ ├── init.go
│ ├── operation.go
│ ├── sys_api.go
│ ├── sys_authority_menu.go
│ ├── sys_base_menu.go
│ ├── user.go
│ └── workflow.go
├── operation
│ └── operation.go
├── user
│ └── user.go
└── workflow
│ └── workflow.go
├── docs
├── docs.go
├── swagger.json
└── swagger.yaml
├── dto
├── authority.go
├── casbin.go
├── common.go
├── kubeDto
│ ├── configmap.go
│ ├── daemonset.go
│ ├── deployment.go
│ ├── ingress.go
│ ├── monitor.go
│ ├── namespace.go
│ ├── node.go
│ ├── persistentVolumeClaim.go
│ ├── persistentvolume.go
│ ├── pod.go
│ ├── secret.go
│ ├── service.go
│ ├── statefulset.go
│ └── workflow.go
├── menu.go
├── operation.go
└── user.go
├── go.mod
├── go.sum
├── img
├── cm_detail.jpg
├── cmdb
│ ├── host.png
│ └── webshell.png
├── dashboard.jpg
├── deployment.jpg
├── namespace.jpg
├── node.jpg
├── operation.png
├── pod.jpg
├── pod_log.jpg
├── pod_ter.jpg
├── rbac
│ ├── api_rbac.png
│ └── menu_rbac.png
├── service.jpg
├── system_state.png
├── user.png
└── wordflow.jpg
├── middleware
├── casbin_rbac.go
├── cors.go
├── jwt.go
├── limiter.go
├── log.go
├── middleware.go
├── operation.go
├── recovery.go
├── response.go
└── translation.go
├── pkg
├── const.go
├── core
│ └── kubemanage
│ │ └── v1
│ │ ├── cloud.go
│ │ ├── interface.go
│ │ ├── kube
│ │ ├── configmap.go
│ │ ├── daemonset.go
│ │ ├── dataselector.go
│ │ ├── deployment.go
│ │ ├── ingress.go
│ │ ├── init.go
│ │ ├── namespace.go
│ │ ├── node.go
│ │ ├── persistentVolumeClaim.go
│ │ ├── persistentvolume.go
│ │ ├── pod.go
│ │ ├── pod_v1.go
│ │ ├── secret.go
│ │ ├── service.go
│ │ └── statefulset.go
│ │ ├── setup.go
│ │ ├── sys
│ │ ├── api.go
│ │ ├── authority.go
│ │ ├── casbin.go
│ │ ├── menu.go
│ │ ├── operation.go
│ │ └── user.go
│ │ ├── system.go
│ │ └── workflow.go
├── globalError
│ └── global_error.go
├── jwt.go
├── logger
│ ├── interface.go
│ └── zap.go
├── params.go
├── password.go
├── source
│ ├── initializer.go
│ ├── mysqlinitHandler.go
│ └── systemInitailzer.go
├── types
│ └── termisnal.go
└── utils
│ ├── auth.go
│ ├── print.go
│ ├── public.go
│ └── signal.go
└── router
└── router.go
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches:
6 | - master
7 | pull_request:
8 | branches:
9 | - master
10 |
11 | env:
12 | GO_VERSION: '1.17.5'
13 |
14 | jobs:
15 |
16 | golang-lint:
17 | runs-on: ubuntu-latest
18 | steps:
19 | - name: Checkout
20 | uses: actions/checkout@v2
21 | with:
22 | submodules: true
23 |
24 | - name: Set up Golang
25 | uses: actions/setup-go@v2
26 | with:
27 | go-version: ${{ env.GO_VERSION }}
28 |
29 | - name: Build the kubemanage binariy
30 | run: go build -v ./...
31 |
32 | - name: Run kubemanage unit test
33 | run: go test -v ./...
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ### JetBrains template
2 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider
3 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
4 |
5 | # User-specific stuff
6 | .idea
7 | .idea/**/workspace.xml
8 | .idea/**/tasks.xml
9 | .idea/**/usage.statistics.xml
10 | .idea/**/dictionaries
11 | .idea/**/shelf
12 |
13 | # Generated files
14 | .idea/**/contentModel.xml
15 |
16 | # Sensitive or high-churn files
17 | .idea/**/dataSources/
18 | .idea/**/dataSources.ids
19 | .idea/**/dataSources.local.xml
20 | .idea/**/sqlDataSources.xml
21 | .idea/**/dynamic.xml
22 | .idea/**/uiDesigner.xml
23 | .idea/**/dbnavigator.xml
24 |
25 | # Gradle
26 | .idea/**/gradle.xml
27 | .idea/**/libraries
28 |
29 | # Gradle and Maven with auto-import
30 | # When using Gradle or Maven with auto-import, you should exclude module files,
31 | # since they will be recreated, and may cause churn. Uncomment if using
32 | # auto-import.
33 | # .idea/artifacts
34 | # .idea/compiler.xml
35 | # .idea/jarRepositories.xml
36 | # .idea/modules.xml
37 | # .idea/*.iml
38 | # .idea/modules
39 | # *.iml
40 | # *.ipr
41 |
42 | # CMake
43 | cmake-build-*/
44 |
45 | # Mongo Explorer plugin
46 | .idea/**/mongoSettings.xml
47 |
48 | # File-based project format
49 | *.iws
50 |
51 | # IntelliJ
52 | out/
53 |
54 | # mpeltonen/sbt-idea plugin
55 | .idea_modules/
56 |
57 | # JIRA plugin
58 | atlassian-ide-plugin.xml
59 |
60 | # Cursive Clojure plugin
61 | .idea/replstate.xml
62 |
63 | # Crashlytics plugin (for Android Studio and IntelliJ)
64 | com_crashlytics_export_strings.xml
65 | crashlytics.properties
66 | crashlytics-build.properties
67 | fabric.properties
68 |
69 | # Editor-based Rest Client
70 | .idea/httpRequests
71 |
72 | # Android studio 3.1+ serialized cache file
73 | .idea/caches/build_file_checksums.ser
74 |
75 | ### Go template
76 | # Binaries for programs and plugins
77 | *.exe
78 | *.exe~
79 | *.dll
80 | *.so
81 | *.dylib
82 |
83 | # Test binary, built with `go test -c`
84 | *.test
85 |
86 | # Output of the go coverage tool, specifically when used with LiteIDE
87 | *.log
88 | *.out
89 |
90 | # Dependency directories (remove the comment below to include it)
91 | # vendor/
92 |
93 |
--------------------------------------------------------------------------------
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 | # Editor-based HTTP Client requests
5 | /httpRequests/
6 | # Datasource local storage ignored files
7 | /dataSources/
8 | /dataSources.local.xml
9 |
--------------------------------------------------------------------------------
/.idea/kubemanage.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.idea/modules.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 noovertime7
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 简体中文 | [English](./README_en.md)
2 | # kubemanage
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | > kubemanage是一个简单易用的K8S管理平台,前端使用vue3,后端使用gin+gorm,对于初学k8s开发的同学来说,是一个很方便练手的项目,也可以作为企业二次开发的模板
19 |
20 | 技术栈选型当下最主流框架,后端使用Gin+GORM,前端使用vite+pinia+VUE3(v3版本)开发,前后端分离开发模式,使用client-go与K8S交互,使用Casbin与动态路由实现RBAC的权限体系
21 |
22 | 前端项目地址 https://github.com/noovertime7/kubemanage-web
23 |
24 | V3版本前端项目地址(开发中) https://gitee.com/noovertime/kubemanage-web.git
25 | ## 开始部署
26 | ### 初始化数据库
27 | 需要手动创建数据库,数据表与数据会通过`DBInitializer`自动初始化
28 |
29 | ```sql
30 | CREATE DATABASE kubemanage;
31 | ```
32 | ### 运行工程
33 | 前端
34 | ```shell
35 | git clone https://github.com/noovertime7/kubemanage-web.git
36 |
37 | cd kubemanage-web
38 |
39 | npm install
40 |
41 | npm run serve
42 | ```
43 | 后端
44 |
45 | 注意:请确保用户名/./kube 文件夹下存在k8s的kubeconfig文件,后面重构为多集群注册模式,容器部署,前端使用V3版本,后端请切换到V3分支
46 |
47 | 开始前请设置配置文件环境变量`KUBEMANAGE-CONFIG`,或通过命令行参数`configFile`指定,配置文件优先级: 默认配置 < 环境变量< 命令行
48 |
49 | ```
50 | git clone https://github.com/noovertime7/kubemanage.git
51 |
52 | cd kubemanage
53 |
54 | go mod tidy
55 |
56 | go run cmd/main.go
57 | ```
58 | 默认用户名密码 admin/kubemanage
59 |
60 | ## 现有特性
61 |
62 | - 支持RBAC的权限管理,根据角色配置菜单权限与接口权限
63 | - 支持资产管理,多主机同步连接,互不影响
64 | - 本地Kubernetes集群的管理
65 | - 接口调用操作审计功能
66 |
67 | ## Roadmap
68 |
69 | - 支持多集群管理
70 | - 支持应用一键发布
71 | - 在线工单审批系统
72 |
73 | ## Issue 规范
74 | - issue 仅用于提交 Bug 或 Feature 以及设计相关的内容,其它内容可能会被直接关闭。
75 |
76 | - 在提交 issue 之前,请搜索相关内容是否已被提出。
77 |
78 | ## Pull Request 规范
79 | - 请先 fork 一份到自己的项目下,在自己项目下新建分支。
80 |
81 | - commit 信息要以`feat(model): 描述信息` 的形式填写,例如 `fix(user): fix xxx bug / feat(user): add xxx`。
82 |
83 | - 如果是修复 bug,请在 PR 中给出描述信息。
84 |
85 | - 合并代码需要两名维护人员参与:一人进行 review 后 approve,另一人再次 review,通过后即可合并。
86 |
87 | ## 生成APi文档
88 |
89 | 使用swag生成api文档
90 |
91 | PS: 请使用最新版本的swag工具,建议拉取最新代码后自行编译,否则会`swag init`初始化失败
92 |
93 | ```shell
94 | swag init --pd -d ./cmd,docs
95 | ```
96 |
97 | 成功生成后访问 `http://127.0.0.1:6180/swagger/index.html`
98 |
99 | ## 效果演示
100 |
101 | 集群详情(v3版本)
102 | 
103 |
104 | 首页
105 | 
106 |
107 | 操作审计(v3版本)
108 | 
109 |
110 | 接口与菜单的RBAC控制(v3版本)
111 | 
112 | 
113 |
114 | 用户管理(v3版本)
115 | 
116 |
117 | 服务状态(v3版本)
118 | 
119 |
120 | CMDB主机管理(v3版本)
121 | 
122 |
123 | CMDB网页终端(v3版本)
124 | 
125 |
126 | 工作流
127 | 
128 |
129 | deployment
130 | 
131 |
132 | 
133 |
134 |
135 | 
136 |
137 | pod
138 | 
139 |
140 | POD日志
141 | 
142 |
143 | POD终端
144 | 
145 |
146 | service
147 | 
148 |
149 | configmap
150 | 
151 |
152 | node
153 | 
154 |
--------------------------------------------------------------------------------
/README_en.md:
--------------------------------------------------------------------------------
1 | English | [简体中文](./README.md)
2 | # kubemanage
3 | Kubemanage is a simple and easy to use K8S management platform. The front end uses vue3 and the back end uses gin+gorm. It is a very convenient project for beginners of K8S development, and can also be used as a template for enterprise secondary development
4 |
5 | Front end project address https://github.com/noovertime7/kubemanage-web
6 | ## Start Deployment
7 | ### Initialize database
8 | The database needs to be created manually, and the data table and data will be initialized automatically through the 'DBInitializer'
9 | ```sql
10 | CREATE DATABASE kubemanage;
11 | ```
12 | ### Operation engineering
13 | front
14 | ```shell
15 | git clone https://github.com/noovertime7/kubemanage-web.git
16 | cd kubemanage-web
17 | npm install
18 | npm run serve
19 | ```
20 | back-end
21 | Note: Please ensure the username// The kubeconfig file of k8s exists in the kube folder. Later, it will be changed to use crd and container deployment
22 |
23 | Before starting, please set the configuration file environment variable KubeManageConfigFile="configuration file location", configuration file priority: default configuration 0 {
49 | return fmt.Errorf("%q does not take any arguments, got %q", cmd.CommandPath(), args)
50 | }
51 | }
52 | return nil
53 | },
54 | }
55 |
56 | // 绑定命令行参数
57 | opts.BindFlags(cmd)
58 | return cmd
59 | }
60 |
61 | func Run(opt *options.Options) error {
62 | // 打印logo
63 | utils.PrintLogo()
64 | // 设置核心应用接口
65 | v1.Setup(opt)
66 | //初始化K8s client TODO 未来移除
67 | InitLocalK8s()
68 | // 初始化 APIs 路由
69 | router.InstallRouters(opt)
70 | // 启动优雅服务
71 | runServer(opt)
72 | return nil
73 | }
74 |
75 | func InitLocalK8s() {
76 | //初始化K8s client
77 | if err := kube.K8s.Init(); err != nil {
78 | utils.Must(err)
79 | }
80 | }
81 |
82 | // 优雅启动貔貅服务
83 | func runServer(opt *options.Options) {
84 | srv := &http.Server{
85 | Addr: fmt.Sprintf("%s", config.SysConfig.Default.ListenAddr),
86 | Handler: opt.GinEngine,
87 | }
88 |
89 | // Initializing the server in a goroutine so that it won't block the graceful shutdown handling below
90 | go func() {
91 | logger.LG.Info("Success", zap.String("starting kubemanage server running on", config.SysConfig.Default.ListenAddr))
92 | if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
93 | logger.LG.Fatal("failed to listen kubemanage server: ", zap.Error(err))
94 | }
95 | }()
96 |
97 | // Wait for interrupt signal to gracefully shut down the server with a timeout of 5 seconds.
98 | quit := utils.SetupSignalHandler()
99 | <-quit
100 | logger.LG.Info("shutting kubemanage server down ...")
101 |
102 | // The context is used to inform the server it has 5 seconds to finish the request
103 | ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
104 | defer cancel()
105 |
106 | if err := srv.Shutdown(ctx); err != nil {
107 | logger.LG.Fatal("kubemanage server forced to shutdown: ", zap.Error(err))
108 | os.Exit(1)
109 | }
110 | logger.LG.Info("kubemanage server exit successful")
111 | }
112 |
--------------------------------------------------------------------------------
/cmd/main.go:
--------------------------------------------------------------------------------
1 | package main
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/cmd/app"
6 | "os"
7 | )
8 |
9 | func main() {
10 | gin.SetMode(gin.ReleaseMode)
11 |
12 | cmd := app.NewServerCommand()
13 | if err := cmd.Execute(); err != nil {
14 | os.Exit(1)
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/config.yaml:
--------------------------------------------------------------------------------
1 | default:
2 | listenAddr: ":6180"
3 | webSocketListenAddr: ""
4 | JWTSecret: "kubemanage"
5 | expireTime: 10
6 |
7 | mysql:
8 | host: "127.0.0.1"
9 | port: "3306"
10 | user: "root"
11 | password: "chenteng"
12 | name: "kubemanage"
13 | maxOpenConns: 100
14 | maxLifetime: 20
15 | maxIdleConns: 10
16 |
17 | log:
18 | level: "debug" ## 日志等级
19 | filename: "kubemanage.log" # 日志文件位置
20 | max_size: 200 # 日志文件最大大小(MB)
21 | max_age: 30 # 保留旧日志文件的最大天数
22 | max_backups: 7 # 最大保留日志个数
--------------------------------------------------------------------------------
/controller/api/api.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/middleware"
7 | v1 "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
8 | "github.com/noovertime7/kubemanage/pkg/globalError"
9 | )
10 |
11 | // GetApiList
12 | // @Tags API
13 | // @Summary 获取API列表
14 | // @Security ApiKeyAuth
15 | // @accept application/json
16 | // @Produce application/json
17 | // @Param data body dto.Empty
18 | // @Success 200 {object} middleware.Response{data=[]model.SysApi,msg=string} "获取API列表"
19 | // @Router /api/sysApi/getAPiList [get]
20 | func (a *apiController) GetApiList(ctx *gin.Context) {
21 | data, err := v1.CoreV1.System().Api().GetApiList(ctx)
22 | if err != nil {
23 | v1.Log.ErrorWithCode(globalError.GetError, err)
24 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
25 | }
26 | middleware.ResponseSuccess(ctx, data)
27 | }
28 |
--------------------------------------------------------------------------------
/controller/api/api_router.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import "github.com/gin-gonic/gin"
4 |
5 | type apiController struct{}
6 |
7 | func NewApiRouter(ginGroup *gin.RouterGroup) {
8 | api := &apiController{}
9 | api.initRoutes(ginGroup)
10 | }
11 |
12 | func (a *apiController) initRoutes(ginGroup *gin.RouterGroup) {
13 | apiRoute := ginGroup.Group("/sysApi")
14 | apiRoute.GET("/getAPiList", a.GetApiList)
15 | }
16 |
--------------------------------------------------------------------------------
/controller/authority/authority.go:
--------------------------------------------------------------------------------
1 | package authority
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/dto"
7 | "github.com/noovertime7/kubemanage/middleware"
8 | v1 "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | )
11 |
12 | func (a *authorityController) GetAuthorityList(ctx *gin.Context) {
13 | params := &dto.PageInfo{}
14 | if err := params.BindingValidParams(ctx); err != nil {
15 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
16 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
17 | return
18 | }
19 | data, err := v1.CoreV1.System().Authority().GetAuthorityList(ctx, *params)
20 | if err != nil {
21 | v1.Log.ErrorWithCode(globalError.GetError, err)
22 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
23 | return
24 | }
25 | middleware.ResponseSuccess(ctx, data)
26 | }
27 |
--------------------------------------------------------------------------------
/controller/authority/authority_router.go:
--------------------------------------------------------------------------------
1 | package authority
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | type authorityController struct{}
8 |
9 | func NewCasbinRouter(ginEngine *gin.RouterGroup) {
10 | cas := authorityController{}
11 | cas.initRoutes(ginEngine)
12 | }
13 |
14 | func (a *authorityController) initRoutes(ginEngine *gin.RouterGroup) {
15 | casRoute := ginEngine.Group("/authority")
16 | {
17 | casRoute.GET("/getPolicyPathByAuthorityId", a.GetPolicyPathByAuthorityId)
18 | casRoute.POST("/updateCasbinByAuthority", a.UpdateCasbinByAuthorityId)
19 | casRoute.GET("/getAuthorityList", a.GetAuthorityList)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/controller/authority/casbin.go:
--------------------------------------------------------------------------------
1 | package authority
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/dto"
7 | "github.com/noovertime7/kubemanage/middleware"
8 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | )
11 |
12 | // GetPolicyPathByAuthorityId
13 | // @Tags Casbin
14 | // @Summary 获取权限列表
15 | // @Security ApiKeyAuth
16 | // @accept application/json
17 | // @Produce application/json
18 | // @Param data body dto.CasbinInReceive true "权限id, 权限模型列表"
19 | // @Success 200 {object} middleware.Response{data=dto.CasbinInfo,msg=string} "获取权限列表,返回包括casbin详情列表"
20 | // @Router /api/authority/getPolicyPathByAuthorityId [get]
21 | func (a *authorityController) GetPolicyPathByAuthorityId(ctx *gin.Context) {
22 | rule := &dto.CasbinInReceive{}
23 | if err := rule.BindingValidParams(ctx); err != nil {
24 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
25 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
26 | return
27 | }
28 | middleware.ResponseSuccess(ctx, v1.CoreV1.System().CasbinService().GetPolicyPathByAuthorityId(rule.AuthorityId))
29 | }
30 |
31 | // UpdateCasbinByAuthorityId
32 | // @Tags Casbin
33 | // @Summary 通过角色更新接口权限
34 | // @Security ApiKeyAuth
35 | // @accept application/json
36 | // @Produce application/json
37 | // @Param data body dto.UpdateCasbinInput true "权限id, 权限模型列表"
38 | // @Success 200 {object} middleware.Response{msg=string} "通过角色更新接口权限"
39 | // @Router /api/authority/updateCasbinByAuthority [post]
40 | func (a *authorityController) UpdateCasbinByAuthorityId(ctx *gin.Context) {
41 | params := &dto.UpdateCasbinInput{}
42 | if err := params.BindingValidParams(ctx); err != nil {
43 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
44 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
45 | return
46 | }
47 | if err := v1.CoreV1.System().CasbinService().UpdateCasbin(params.AuthorityId, params.CasbinInfo); err != nil {
48 | v1.Log.ErrorWithCode(globalError.UpdateError, err)
49 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.UpdateError, err))
50 | return
51 | }
52 | middleware.ResponseSuccess(ctx, "")
53 | }
54 |
--------------------------------------------------------------------------------
/controller/kubeController/kubeRouter.go:
--------------------------------------------------------------------------------
1 | package kubeController
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | type kubeRouter struct{}
8 |
9 | func NewKubeRouter(ginEngine *gin.RouterGroup) {
10 | k := kubeRouter{}
11 | k.initRoutes(ginEngine)
12 | }
13 |
14 | func (k *kubeRouter) initRoutes(ginEngine *gin.RouterGroup) {
15 | k8sRoute := ginEngine.Group("/k8s")
16 | {
17 | k8sRoute.POST("/deployment/create", Deployment.CreateDeployment)
18 | k8sRoute.DELETE("/deployment/del", Deployment.DeleteDeployment)
19 | k8sRoute.PUT("/deployment/update", Deployment.UpdateDeployment)
20 | k8sRoute.GET("/deployment/list", Deployment.GetDeploymentList)
21 | k8sRoute.GET("/deployment/detail", Deployment.GetDeploymentDetail)
22 | k8sRoute.PUT("/deployment/restart", Deployment.RestartDeployment)
23 | k8sRoute.GET("/deployment/scale", Deployment.ScaleDeployment)
24 | k8sRoute.GET("/deployment/numnp", Deployment.GetDeploymentNumPreNS)
25 | }
26 | {
27 | k8sRoute.GET("/pod/list", Pod.GetPods)
28 | k8sRoute.GET("/pod/detail", Pod.GetPodDetail)
29 | k8sRoute.DELETE("/pod/del", Pod.DeletePod)
30 | k8sRoute.PUT("/pod/update", Pod.UpdatePod)
31 | k8sRoute.GET("/pod/container", Pod.GetPodContainer)
32 | k8sRoute.GET("/pod/log", Pod.GetPodLog)
33 | k8sRoute.GET("/pod/numnp", Pod.GetPodNumPreNp)
34 | k8sRoute.GET("/pod/webshell", Pod.WebShell)
35 | }
36 | {
37 | k8sRoute.DELETE("/daemonset/del", DaemonSet.DeleteDaemonSet)
38 | k8sRoute.PUT("/daemonset/update", DaemonSet.UpdateDaemonSet)
39 | k8sRoute.GET("/daemonset/list", DaemonSet.GetDaemonSetList)
40 | k8sRoute.GET("/daemonset/detail", DaemonSet.GetDaemonSetDetail)
41 | }
42 | {
43 | k8sRoute.DELETE("/statefulset/del", StatefulSet.DeleteStatefulSet)
44 | k8sRoute.PUT("/statefulset/update", StatefulSet.UpdateStatefulSet)
45 | k8sRoute.GET("/statefulset/list", StatefulSet.GetStatefulSetList)
46 | k8sRoute.GET("/statefulset/detail", StatefulSet.GetStatefulSetDetail)
47 | }
48 | {
49 | k8sRoute.GET("/node/list", Node.GetNodeList)
50 | k8sRoute.GET("/node/detail", Node.GetNodeDetail)
51 | }
52 |
53 | {
54 | k8sRoute.PUT("/namespace/create", NameSpace.CreateNameSpace)
55 | k8sRoute.DELETE("/namespace/del", NameSpace.DeleteNameSpace)
56 | k8sRoute.GET("/namespace/list", NameSpace.GetNameSpaceList)
57 | k8sRoute.GET("/namespace/detail", NameSpace.GetNameSpaceDetail)
58 | }
59 |
60 | {
61 | k8sRoute.DELETE("/persistentvolume/del", PersistentVolume.DeletePersistentVolume)
62 | k8sRoute.GET("/persistentvolume/list", PersistentVolume.GetPersistentVolumeList)
63 | k8sRoute.GET("/persistentvolume/detail", PersistentVolume.GetPersistentVolumeDetail)
64 | }
65 |
66 | {
67 | k8sRoute.POST("/service/create", ServiceController.CreateService)
68 | k8sRoute.DELETE("/service/del", ServiceController.DeleteService)
69 | k8sRoute.PUT("/service/update", ServiceController.UpdateService)
70 | k8sRoute.GET("/service/list", ServiceController.GetServiceList)
71 | k8sRoute.GET("/service/detail", ServiceController.GetServiceDetail)
72 | k8sRoute.GET("/service/numnp", ServiceController.GetServicePerNS)
73 | }
74 |
75 | {
76 | k8sRoute.PUT("/ingress/create", IngressController.CreateIngress)
77 | k8sRoute.DELETE("/ingress/del", IngressController.DeleteIngress)
78 | k8sRoute.PUT("/ingress/update", IngressController.UpdateIngress)
79 | k8sRoute.GET("/ingress/list", IngressController.GetIngressList)
80 | k8sRoute.GET("/ingress/detail", IngressController.GetIngressDetail)
81 | k8sRoute.GET("/ingress/numnp", IngressController.GetIngressNumPreNp)
82 | }
83 |
84 | {
85 | k8sRoute.DELETE("/configmap/del", Configmap.DeleteConfigmap)
86 | k8sRoute.PUT("/configmap/update", Configmap.UpdateConfigmap)
87 | k8sRoute.GET("/configmap/list", Configmap.GetConfigmapList)
88 | k8sRoute.GET("/configmap/detail", Configmap.GetConfigmapDetail)
89 | }
90 |
91 | {
92 | k8sRoute.DELETE("/persistentvolumeclaim/del", PersistentVolumeClaim.DeletePersistentVolumeClaim)
93 | k8sRoute.PUT("/persistentvolumeclaim/update", PersistentVolumeClaim.UpdatePersistentVolumeClaim)
94 | k8sRoute.GET("/persistentvolumeclaim/list", PersistentVolumeClaim.GetPersistentVolumeClaimList)
95 | k8sRoute.GET("/persistentvolumeclaim/detail", PersistentVolumeClaim.GetPersistentVolumeClaimDetail)
96 | }
97 |
98 | {
99 | k8sRoute.DELETE("/secret/del", Secret.DeleteSecret)
100 | k8sRoute.PUT("/secret/update", Secret.UpdateSecret)
101 | k8sRoute.GET("/secret/list", Secret.GetSecretList)
102 | k8sRoute.GET("/secret/detail", Secret.GetSecretDetail)
103 | }
104 |
105 | {
106 | k8sRoute.POST("/workflow/create", WorkFlow.CreateWorkFlow)
107 | k8sRoute.DELETE("/workflow/del", WorkFlow.DeleteWorkflow)
108 | k8sRoute.GET("/workflow/list", WorkFlow.GetWorkflowList)
109 | k8sRoute.GET("/workflow/id", WorkFlow.GetWorkflowByID)
110 | }
111 |
112 | }
113 |
--------------------------------------------------------------------------------
/controller/kubeController/namespace.go:
--------------------------------------------------------------------------------
1 | package kubeController
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/dto/kubeDto"
6 | "github.com/noovertime7/kubemanage/middleware"
7 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
8 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1/kube"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | )
11 |
12 | var NameSpace namespace
13 |
14 | type namespace struct{}
15 |
16 | // CreateNameSpace 创建namespace
17 | // ListPage godoc
18 | // @Summary 创建namespace
19 | // @Description 创建namespace
20 | // @Tags NameSpace
21 | // @ID /api/k8s/namespace/create
22 | // @Accept json
23 | // @Produce json
24 | // @Param name query string true "namespace名称"
25 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": "创建成功}"
26 | // @Router /api/k8s/namespace/create [put]
27 | func (n *namespace) CreateNameSpace(ctx *gin.Context) {
28 | params := &kubeDto.NameSpaceNameInput{}
29 | if err := params.BindingValidParams(ctx); err != nil {
30 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
31 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
32 | return
33 | }
34 | if err := kube.NameSpace.CreateNameSpace(params.Name); err != nil {
35 | v1.Log.ErrorWithCode(globalError.CreateError, err)
36 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.CreateError, err))
37 | return
38 | }
39 | middleware.ResponseSuccess(ctx, "创建成功")
40 | }
41 |
42 | // DeleteNameSpace 删除namespace
43 | // ListPage godoc
44 | // @Summary 删除namespace
45 | // @Description 删除namespace
46 | // @Tags NameSpace
47 | // @ID /api/k8s/namespace/del
48 | // @Accept json
49 | // @Produce json
50 | // @Param name query string true "namespace名称"
51 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": "删除成功}"
52 | // @Router /api/k8s/namespace/del [delete]
53 | func (n *namespace) DeleteNameSpace(ctx *gin.Context) {
54 | params := &kubeDto.NameSpaceNameInput{}
55 | if err := params.BindingValidParams(ctx); err != nil {
56 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
57 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
58 | return
59 | }
60 | if err := kube.NameSpace.DeleteNameSpace(params.Name); err != nil {
61 | v1.Log.ErrorWithCode(globalError.DeleteError, err)
62 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.DeleteError, err))
63 | return
64 | }
65 | middleware.ResponseSuccess(ctx, "删除成功")
66 | }
67 |
68 | // GetNameSpaceList 获取NameSpace列表
69 | // ListPage godoc
70 | // @Summary 获取NameSpace列表
71 | // @Description 获取NameSpace列表
72 | // @Tags NameSpace
73 | // @ID /api/k8s/namespace/list
74 | // @Accept json
75 | // @Produce json
76 | // @Param filter_name query string false "过滤"
77 | // @Param page query int false "页码"
78 | // @Param limit query int false "分页限制"
79 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": service.NameSpaceResp}"
80 | // @Router /api/k8s/namespace/list [get]
81 | func (n *namespace) GetNameSpaceList(ctx *gin.Context) {
82 | params := &kubeDto.NameSpaceListInput{}
83 | if err := params.BindingValidParams(ctx); err != nil {
84 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
85 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
86 | return
87 | }
88 | data, err := kube.NameSpace.GetNameSpaces(params.FilterName, params.Limit, params.Page)
89 | if err != nil {
90 | v1.Log.ErrorWithCode(globalError.GetError, err)
91 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
92 | return
93 | }
94 | middleware.ResponseSuccess(ctx, data)
95 | }
96 |
97 | // GetNameSpaceDetail 获取NameSpace详情
98 | // ListPage godoc
99 | // @Summary 获取NameSpace详情
100 | // @Description 获取NameSpace详情
101 | // @Tags NameSpace
102 | // @ID /api/k8s/namespace/detail
103 | // @Accept json
104 | // @Produce json
105 | // @Param name query string true "namespace名称"
106 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data":data }"
107 | // @Router /api/k8s/namespace/detail [get]
108 | func (n *namespace) GetNameSpaceDetail(ctx *gin.Context) {
109 | params := &kubeDto.NameSpaceNameInput{}
110 | if err := params.BindingValidParams(ctx); err != nil {
111 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
112 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
113 | return
114 | }
115 | data, err := kube.NameSpace.GetNameSpacesDetail(params.Name)
116 | if err != nil {
117 | v1.Log.ErrorWithCode(globalError.GetError, err)
118 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
119 | return
120 | }
121 | middleware.ResponseSuccess(ctx, data)
122 | }
123 |
--------------------------------------------------------------------------------
/controller/kubeController/node.go:
--------------------------------------------------------------------------------
1 | package kubeController
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/dto/kubeDto"
6 | "github.com/noovertime7/kubemanage/middleware"
7 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
8 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1/kube"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | )
11 |
12 | var Node node
13 |
14 | type node struct{}
15 |
16 | // GetNodeList 获取Node列表
17 | // ListPage godoc
18 | // @Summary 获取Node列表
19 | // @Description 获取Node列表
20 | // @Tags Node
21 | // @ID /api/k8s/node/list
22 | // @Accept json
23 | // @Produce json
24 | // @Param filter_name query string false "过滤"
25 | // @Param page query int false "页码"
26 | // @Param limit query int false "分页限制"
27 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": service.NameSpaceResp}"
28 | // @Router /api/k8s/node/list [get]
29 | func (n *node) GetNodeList(ctx *gin.Context) {
30 | params := &kubeDto.NodeListInput{}
31 | if err := params.BindingValidParams(ctx); err != nil {
32 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
33 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
34 | return
35 | }
36 | data, err := kube.Node.GetNodes(params.FilterName, params.Limit, params.Page)
37 | if err != nil {
38 | v1.Log.ErrorWithCode(globalError.GetError, err)
39 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
40 | return
41 | }
42 | middleware.ResponseSuccess(ctx, data)
43 | }
44 |
45 | // GetNodeDetail 获取Node详情
46 | // ListPage godoc
47 | // @Summary 获取Node详情
48 | // @Description 获取Node详情
49 | // @Tags Node
50 | // @ID /api/k8s/node/detail
51 | // @Accept json
52 | // @Produce json
53 | // @Param name query string true "node名称"
54 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data":data }"
55 | // @Router /api/k8s/node/detail [get]
56 | func (n *node) GetNodeDetail(ctx *gin.Context) {
57 | params := &kubeDto.NodeNameInput{}
58 | if err := params.BindingValidParams(ctx); err != nil {
59 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
60 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
61 | return
62 | }
63 | data, err := kube.Node.GetNodeDetail(params.Name)
64 | if err != nil {
65 | v1.Log.ErrorWithCode(globalError.GetError, err)
66 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
67 | return
68 | }
69 | middleware.ResponseSuccess(ctx, data)
70 | }
71 |
--------------------------------------------------------------------------------
/controller/kubeController/persistentvolume.go:
--------------------------------------------------------------------------------
1 | package kubeController
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/dto/kubeDto"
6 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
7 |
8 | "github.com/noovertime7/kubemanage/middleware"
9 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1/kube"
10 | "github.com/noovertime7/kubemanage/pkg/globalError"
11 | )
12 |
13 | var PersistentVolume persistentVolume
14 |
15 | type persistentVolume struct{}
16 |
17 | // DeletePersistentVolume 删除persistentVolume
18 | // ListPage godoc
19 | // @Summary 删除persistentVolume
20 | // @Description 删除persistentVolume
21 | // @Tags PersistentVolume
22 | // @ID /api/k8s/spersistentvolume/del
23 | // @Accept json
24 | // @Produce json
25 | // @Param name query string true "persistentvolume名称"
26 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": "删除成功}"
27 | // @Router /api/k8s/spersistentvolume/del [delete]
28 | func (n *persistentVolume) DeletePersistentVolume(ctx *gin.Context) {
29 | params := &kubeDto.PersistentVolumeNameInput{}
30 | if err := params.BindingValidParams(ctx); err != nil {
31 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
32 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
33 | return
34 | }
35 | if err := kube.PersistentVolume.DeletePersistentVolume(params.Name); err != nil {
36 | v1.Log.ErrorWithCode(globalError.GetError, err)
37 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
38 | return
39 | }
40 | middleware.ResponseSuccess(ctx, "删除成功")
41 | }
42 |
43 | // GetPersistentVolumeList 获取PV列表
44 | // ListPage godoc
45 | // @Summary 获取PV列表
46 | // @Description 获取PV列表
47 | // @Tags PersistentVolume
48 | // @ID /api/k8s/persistentvolume/list
49 | // @Accept json
50 | // @Produce json
51 | // @Param filter_name query string false "过滤"
52 | // @Param page query int false "页码"
53 | // @Param limit query int false "分页限制"
54 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": service.PersistentVolumeResp}"
55 | // @Router /api/k8s/persistentvolume/list [get]
56 | func (n *persistentVolume) GetPersistentVolumeList(ctx *gin.Context) {
57 | params := &kubeDto.PersistentVolumeListInput{}
58 | if err := params.BindingValidParams(ctx); err != nil {
59 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
60 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
61 | return
62 | }
63 | data, err := kube.PersistentVolume.GetPersistentVolumes(params.FilterName, params.Limit, params.Page)
64 | if err != nil {
65 | v1.Log.ErrorWithCode(globalError.GetError, err)
66 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
67 | return
68 | }
69 | middleware.ResponseSuccess(ctx, data)
70 | }
71 |
72 | // GetPersistentVolumeDetail 获取PV的详细信息
73 | // ListPage godoc
74 | // @Summary 获取PV的详细信息
75 | // @Description 获取PV的详细信息
76 | // @Tags PersistentVolume
77 | // @ID /api/k8s/persistentvolume/detail
78 | // @Accept json
79 | // @Produce json
80 | // @Param name query string true "persistentVolume名称"
81 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": *coreV1.PersistentVolume}"
82 | // @Router /api/k8s/persistentvolume/detail [get]
83 | func (n *persistentVolume) GetPersistentVolumeDetail(ctx *gin.Context) {
84 | params := &kubeDto.PersistentVolumeNameInput{}
85 | if err := params.BindingValidParams(ctx); err != nil {
86 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
87 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
88 | return
89 | }
90 | data, err := kube.PersistentVolume.GetPersistentVolumesDetail(params.Name)
91 | if err != nil {
92 | v1.Log.ErrorWithCode(globalError.GetError, err)
93 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
94 | return
95 | }
96 | middleware.ResponseSuccess(ctx, data)
97 | }
98 |
--------------------------------------------------------------------------------
/controller/kubeController/workflow.go:
--------------------------------------------------------------------------------
1 | package kubeController
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/dto/kubeDto"
6 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
7 |
8 | "github.com/noovertime7/kubemanage/middleware"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | )
11 |
12 | var WorkFlow workflow
13 |
14 | type workflow struct{}
15 |
16 | // CreateWorkFlow 创建workflow
17 | // ListPage godoc
18 | // @Summary 创建workflow
19 | // @Description 创建workflow
20 | // @Tags Workflow
21 | // @ID /api/k8s/workflow/create
22 | // @Accept json
23 | // @Produce json
24 | // @Param body body kubernetes.WorkFlowCreateInput true "body"
25 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": "创建成功}"
26 | // @Router /api/k8s/workflow/create [post]
27 | func (w *workflow) CreateWorkFlow(ctx *gin.Context) {
28 | params := &kubeDto.WorkFlowCreateInput{}
29 | if err := params.BindingValidParams(ctx); err != nil {
30 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
31 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
32 | return
33 | }
34 | if err := v1.CoreV1.WorkFlow().Save(ctx, params); err != nil {
35 | v1.Log.ErrorWithCode(globalError.CreateError, err)
36 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.CreateError, err))
37 | return
38 | }
39 | middleware.ResponseSuccess(ctx, "创建成功")
40 | }
41 |
42 | // DeleteWorkflow 删除Workflow
43 | // ListPage godoc
44 | // @Summary 删除Workflow
45 | // @Description 删除Workflow
46 | // @Tags Workflow
47 | // @ID /api/k8s/workflow/del
48 | // @Accept json
49 | // @Produce json
50 | // @Param ID query int true "Workflow ID"
51 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": "删除成功}"
52 | // @Router /api/k8s/workflow/del [delete]
53 | func (w *workflow) DeleteWorkflow(ctx *gin.Context) {
54 | params := &kubeDto.WorkFlowIDInput{}
55 | if err := params.BindingValidParams(ctx); err != nil {
56 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
57 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
58 | return
59 | }
60 | if err := v1.CoreV1.WorkFlow().Delete(ctx, params.ID); err != nil {
61 | v1.Log.ErrorWithCode(globalError.DeleteError, err)
62 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.DeleteError, err))
63 | return
64 | }
65 | middleware.ResponseSuccess(ctx, "删除成功")
66 | }
67 |
68 | // GetWorkflowList 查看Configmap列表
69 | // ListPage godoc
70 | // @Summary 查看Configmap列表
71 | // @Description 查看Configmap列表
72 | // @Tags Workflow
73 | // @ID /api/k8s/workflow/list
74 | // @Accept json
75 | // @Produce json
76 | // @Param filter_name query string false "过滤"
77 | // @Param page query int false "页码"
78 | // @Param limit query int false "分页限制"
79 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": }"
80 | // @Router /api/k8s/workflow/list [get]
81 | func (w *workflow) GetWorkflowList(ctx *gin.Context) {
82 | params := &kubeDto.WorkFlowListInput{}
83 | if err := params.BindingValidParams(ctx); err != nil {
84 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
85 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
86 | return
87 | }
88 | data, err := v1.CoreV1.WorkFlow().FindList(ctx, params)
89 | if err != nil {
90 | v1.Log.ErrorWithCode(globalError.GetError, err)
91 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
92 | return
93 | }
94 | middleware.ResponseSuccess(ctx, data)
95 | }
96 |
97 | // GetWorkflowByID 根据ID查看workflow
98 | // ListPage godoc
99 | // @Summary 根据ID查看workflow
100 | // @Description 根据ID查看workflow
101 | // @Tags Workflow
102 | // @ID /api/k8s/workflow/id
103 | // @Accept json
104 | // @Produce json
105 | // @Param ID query int true "Workflow ID"
106 | // @Success 200 {object} middleware.Response"{"code": 200, msg="","data": }"
107 | // @Router /api/k8s/workflow/id [get]
108 | func (w *workflow) GetWorkflowByID(ctx *gin.Context) {
109 | params := &kubeDto.WorkFlowIDInput{}
110 | if err := params.BindingValidParams(ctx); err != nil {
111 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
112 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
113 | return
114 | }
115 | data, err := v1.CoreV1.WorkFlow().Find(ctx, params)
116 | if err != nil {
117 | v1.Log.ErrorWithCode(globalError.GetError, err)
118 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
119 | return
120 | }
121 | middleware.ResponseSuccess(ctx, data)
122 | }
123 |
--------------------------------------------------------------------------------
/controller/menu/menu.go:
--------------------------------------------------------------------------------
1 | package menu
2 |
3 | import (
4 | "fmt"
5 | "github.com/gin-gonic/gin"
6 | "github.com/noovertime7/kubemanage/dto"
7 | "github.com/noovertime7/kubemanage/middleware"
8 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | "github.com/noovertime7/kubemanage/pkg/utils"
11 | )
12 |
13 | // GetMenusByAuthID
14 | // @Tags AuthorityMenu
15 | // @Summary 获取用户动态路由
16 | // @Security ApiKeyAuth
17 | // @Produce application/json
18 | // @Param data body dto.Empty true "空"
19 | // @Success 200 {object} middleware.Response{data=dto.SysBaseMenusResponse,msg=string} "获取用户动态路由,返回包括系统菜单详情列表"
20 | // @Router /api/menu/:authID/getMenuByAuthID [get]
21 | func (m *menuController) GetMenusByAuthID(ctx *gin.Context) {
22 | authID, err := utils.ParseUint(ctx.Param("authID"))
23 | if err != nil || authID == 0 {
24 | v1.Log.ErrorWithCode(globalError.ParamBindError, fmt.Errorf("authID empty"))
25 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, fmt.Errorf("authID empty")))
26 | }
27 | menus, err := v1.CoreV1.System().Menu().GetMenuByAuthorityID(ctx, authID)
28 | if err != nil {
29 | v1.Log.ErrorWithCode(globalError.GetError, err)
30 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
31 | return
32 | }
33 | middleware.ResponseSuccess(ctx, &dto.SysMenusResponse{Menus: menus})
34 | }
35 |
36 | // GetBaseMenus
37 | // @Tags AuthorityMenu
38 | // @Summary 获取用户动态路由
39 | // @Security ApiKeyAuth
40 | // @Produce application/json
41 | // @Param data body dto.Empty true "空"
42 | // @Success 200 {object} middleware.Response{data=dto.SysBaseMenusResponse,msg=string} "获取系统菜单详情列表"
43 | // @Router /api/menu/getBaseMenuTree [get]
44 | func (m *menuController) GetBaseMenus(ctx *gin.Context) {
45 | menus, err := v1.CoreV1.System().Menu().GetBassMenu(ctx)
46 | if err != nil {
47 | v1.Log.ErrorWithCode(globalError.GetError, err)
48 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
49 | return
50 | }
51 | middleware.ResponseSuccess(ctx, menus)
52 | }
53 |
54 | // AddBaseMenu
55 | // @Tags Menu
56 | // @Summary 新增菜单
57 | // @Security ApiKeyAuth
58 | // @accept application/json
59 | // @Produce application/json
60 | // @Param data body model.SysBaseMenu true "路由path, 父菜单ID, 路由name, 对应前端文件路径, 排序标记"
61 | // @Success 200 {object} middleware.Response{msg=string} "新增菜单"
62 | // @Router /api/menu/add_base_menu [post]
63 | func (m *menuController) AddBaseMenu(ctx *gin.Context) {
64 | params := &dto.AddSysMenusInput{}
65 | if err := params.BindingValidParams(ctx); err != nil {
66 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
67 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
68 | }
69 | if err := v1.CoreV1.System().Menu().AddBaseMenu(ctx, params); err != nil {
70 | v1.Log.ErrorWithCode(globalError.CreateError, err)
71 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.CreateError, err))
72 | return
73 | }
74 | middleware.ResponseSuccess(ctx, "添加成功")
75 | }
76 |
77 | // AddMenuAuthority
78 | // @Tags AuthorityMenu
79 | // @Summary 增加menu和角色关联关系
80 | // @Security ApiKeyAuth
81 | // @accept application/json
82 | // @Produce application/json
83 | // @Param data body dto.AddMenuAuthorityInput true "角色ID"
84 | // @Success 200 {object} response.Response{msg=string} "增加menu和角色关联关系"
85 | // @Router /api/menu/add_menu_authority [post]
86 | func (m *menuController) AddMenuAuthority(ctx *gin.Context) {
87 | params := &dto.AddMenuAuthorityInput{}
88 | if err := params.BindingValidParams(ctx); err != nil {
89 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
90 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
91 | }
92 | if err := v1.CoreV1.System().Menu().AddMenuAuthority(ctx, params.Menus, params.AuthorityId); err != nil {
93 | v1.Log.ErrorWithCode(globalError.ServerError, err)
94 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ServerError, err))
95 | }
96 | middleware.ResponseSuccess(ctx, "添加成功")
97 | }
98 |
--------------------------------------------------------------------------------
/controller/menu/menu_router.go:
--------------------------------------------------------------------------------
1 | package menu
2 |
3 | import "github.com/gin-gonic/gin"
4 |
5 | type menuController struct{}
6 |
7 | func NewMenuRouter(ginEngine *gin.RouterGroup) {
8 | menu := menuController{}
9 | menu.initRoutes(ginEngine)
10 | }
11 |
12 | func (m *menuController) initRoutes(ginEngine *gin.RouterGroup) {
13 | menuRoute := ginEngine.Group("/menu")
14 | menu := &menuController{}
15 | {
16 | menuRoute.GET("/:authID/getMenuByAuthID", menu.GetMenusByAuthID)
17 | menuRoute.GET("/getBaseMenuTree", menu.GetBaseMenus)
18 | menuRoute.POST("/add_base_menu", menu.AddBaseMenu)
19 | menuRoute.POST("/add_menu_authority", menu.AddMenuAuthority)
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/controller/operation/operation.go:
--------------------------------------------------------------------------------
1 | package operation
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
6 |
7 | "github.com/noovertime7/kubemanage/dto"
8 | "github.com/noovertime7/kubemanage/middleware"
9 | "github.com/noovertime7/kubemanage/pkg/globalError"
10 | "github.com/noovertime7/kubemanage/pkg/utils"
11 | )
12 |
13 | // GetOperationRecordList
14 | // @Tags SysOperationRecord
15 | // @Summary 分页获取SysOperationRecord列表
16 | // @Security ApiKeyAuth
17 | // @accept application/json
18 | // @Produce application/json
19 | // @Param data query dto.OperationListInput true "页码, 每页大小, 搜索条件"
20 | // @Success 200 {object} middleware.Response{data=dto.OperationListOutPut,msg=string} "分页获取SysOperationRecord列表,返回包括列表,总数,页码,每页数量"
21 | // @Router /api/operation/get_operations [get]
22 | func (o *operationController) GetOperationRecordList(ctx *gin.Context) {
23 | params := &dto.OperationListInput{}
24 | if err := params.BindingValidParams(ctx); err != nil {
25 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
26 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
27 | return
28 | }
29 | data, err := v1.CoreV1.System().Operation().GetPageList(ctx, params)
30 | if err != nil {
31 | v1.Log.ErrorWithErr("查询失败", err)
32 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.GetError, err))
33 | return
34 | }
35 | middleware.ResponseSuccess(ctx, data)
36 | }
37 |
38 | // DeleteOperationRecord
39 | // @Tags SysOperationRecord
40 | // @Summary 删除SysOperationRecord
41 | // @Security ApiKeyAuth
42 | // @accept application/json
43 | // @Produce application/json
44 | // @Param data body dto.Empty
45 | // @Success 200 {object} middleware.Response{msg=string} "删除SysOperationRecord"
46 | // @Router /api/operation/{id}/delete_operation [delete]
47 | func (o *operationController) DeleteOperationRecord(ctx *gin.Context) {
48 | recordId, err := utils.ParseInt(ctx.Param("id"))
49 | if err != nil {
50 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
51 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
52 | }
53 | if err := v1.CoreV1.System().Operation().DeleteRecord(ctx, recordId); err != nil {
54 | v1.Log.ErrorWithCode(globalError.DeleteError, err)
55 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.DeleteError, err))
56 | }
57 | middleware.ResponseSuccess(ctx, "删除成功")
58 | }
59 |
60 | // DeleteOperationRecords
61 | // @Tags SysOperationRecord
62 | // @Summary 删除SysOperationRecord
63 | // @Security ApiKeyAuth
64 | // @accept application/json
65 | // @Produce application/json
66 | // @Param data body dto.IdsReq
67 | // @Success 200 {object} middleware.Response{msg=string} "删除SysOperationRecord"
68 | // @Router /api/operation/delete_operations [delete]
69 | func (o *operationController) DeleteOperationRecords(ctx *gin.Context) {
70 | params := &dto.IdsReq{}
71 | if err := params.BindingValidParams(ctx); err != nil {
72 | v1.Log.ErrorWithCode(globalError.ParamBindError, err)
73 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.ParamBindError, err))
74 | return
75 | }
76 | if err := v1.CoreV1.System().Operation().DeleteRecords(ctx, params.Ids); err != nil {
77 | v1.Log.ErrorWithErr("批量删除失败", err)
78 | middleware.ResponseError(ctx, globalError.NewGlobalError(globalError.DeleteError, err))
79 | return
80 | }
81 | middleware.ResponseSuccess(ctx, "删除成功")
82 | }
83 |
--------------------------------------------------------------------------------
/controller/operation/operation_router.go:
--------------------------------------------------------------------------------
1 | package operation
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | )
6 |
7 | type operationController struct{}
8 |
9 | func NewOperationRouter(ginEngine *gin.RouterGroup) {
10 | opera := operationController{}
11 | opera.initRoutes(ginEngine)
12 | }
13 |
14 | func (o *operationController) initRoutes(ginEngine *gin.RouterGroup) {
15 | operaRoute := ginEngine.Group("/operation")
16 | opera := &operationController{}
17 | {
18 | operaRoute.GET("/get_operations", opera.GetOperationRecordList)
19 | operaRoute.DELETE("/:id/delete_operation", opera.DeleteOperationRecord)
20 | operaRoute.POST("/delete_operations", opera.DeleteOperationRecords)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/controller/other/swagger.go:
--------------------------------------------------------------------------------
1 | package other
2 |
3 | // @title Swagger Example API
4 | // @version 1.0
5 | // @description This is a sample server celler server.
6 | // @termsOfService http://swagger.io/terms/
7 |
8 | // @contact.name API Support
9 | // @contact.url http://www.swagger.io/support
10 | // @contact.email support@swagger.io
11 |
12 | // @license.name Apache 2.0
13 | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html
14 |
15 | // @host localhost:8080
16 | // @BasePath /api/v1
17 | // @query.collection.format multi
18 |
19 | // @securityDefinitions.basic BasicAuth
20 |
21 | // @securityDefinitions.apikey ApiKeyAuth
22 | // @in header
23 | // @name Authorization
24 |
25 | // @securitydefinitions.oauth2.application OAuth2Application
26 | // @tokenUrl https://example.com/oauth/token
27 | // @scope.write Grants write access
28 | // @scope.admin Grants read and write access to administrative information
29 |
30 | // @securitydefinitions.oauth2.implicit OAuth2Implicit
31 | // @authorizationurl https://example.com/oauth/authorize
32 | // @scope.write Grants write access
33 | // @scope.admin Grants read and write access to administrative information
34 |
35 | // @securitydefinitions.oauth2.password OAuth2Password
36 | // @tokenUrl https://example.com/oauth/token
37 | // @scope.read Grants read access
38 | // @scope.write Grants write access
39 | // @scope.admin Grants read and write access to administrative information
40 |
41 | // @securitydefinitions.oauth2.accessCode OAuth2AccessCode
42 | // @tokenUrl https://example.com/oauth/token
43 | // @authorizationurl https://example.com/oauth/authorize
44 | // @scope.admin Grants read and write access to administrative information
45 |
46 | // @x-extension-openapi {"example": "value on a json format"}
47 |
48 | import (
49 | "github.com/gin-gonic/gin"
50 | "github.com/noovertime7/kubemanage/docs"
51 | swaggerFiles "github.com/swaggo/files"
52 | ginSwagger "github.com/swaggo/gin-swagger"
53 | )
54 |
55 | func NewSwaggarRoute(ginEngine *gin.RouterGroup) {
56 | // programmatically set swagger info
57 | docs.SwaggerInfo.Title = "Kubemanage API"
58 | docs.SwaggerInfo.Description = "Kubemanage"
59 | docs.SwaggerInfo.Version = "1.0"
60 | docs.SwaggerInfo.Host = "127.0.0.1:6180"
61 | docs.SwaggerInfo.BasePath = ""
62 | docs.SwaggerInfo.Schemes = []string{"http", "https"}
63 | ginEngine.GET("/swagger/*any", ginSwagger.WrapHandler(swaggerFiles.Handler))
64 | }
65 |
--------------------------------------------------------------------------------
/controller/user/user_router.go:
--------------------------------------------------------------------------------
1 | package user
2 |
3 | import "github.com/gin-gonic/gin"
4 |
5 | type userController struct{}
6 |
7 | func NewUserRouter(ginEngine *gin.RouterGroup) {
8 | u := userController{}
9 | u.initRoutes(ginEngine)
10 | }
11 |
12 | func (u *userController) initRoutes(ginEngine *gin.RouterGroup) {
13 | userRoute := ginEngine.Group("/user")
14 | user := &userController{}
15 | {
16 | userRoute.POST("/login", user.Login)
17 | userRoute.GET("/loginout", user.LoginOut)
18 | userRoute.GET("/getinfo", user.GetUserInfo)
19 | userRoute.PUT("/:id/set_auth", user.SetUserAuthority)
20 | userRoute.DELETE("/:id/delete_user", user.DeleteUser)
21 | userRoute.POST("/:id/change_pwd", user.ChangePassword)
22 | userRoute.PUT("/:id/reset_pwd", user.ResetPassword)
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/dao/api/api.go:
--------------------------------------------------------------------------------
1 | package api
2 |
3 | import (
4 | "context"
5 |
6 | "gorm.io/gorm"
7 |
8 | "github.com/noovertime7/kubemanage/dao/model"
9 | )
10 |
11 | type APi interface {
12 | FindList(ctx context.Context, search model.SysApi) ([]model.SysApi, error)
13 | }
14 |
15 | var _ APi = &api{}
16 |
17 | func NewApi(db *gorm.DB) APi {
18 | return &api{db: db}
19 | }
20 |
21 | type api struct {
22 | db *gorm.DB
23 | }
24 |
25 | func (a *api) FindList(ctx context.Context, search model.SysApi) ([]model.SysApi, error) {
26 | var out []model.SysApi
27 | return out, a.db.WithContext(ctx).Where(&search).Find(&out).Error
28 | }
29 |
--------------------------------------------------------------------------------
/dao/authority/authority.go:
--------------------------------------------------------------------------------
1 | package authority
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "github.com/noovertime7/kubemanage/dto"
7 | "gorm.io/gorm"
8 | )
9 |
10 | type Authority interface {
11 | Find(ctx context.Context, authInfo *model.SysAuthority) (*model.SysAuthority, error)
12 | FindList(ctx context.Context, authInfo *model.SysAuthority) ([]*model.SysAuthority, error)
13 | Save(ctx context.Context, authInfo *model.SysAuthority) error
14 | Updates(ctx context.Context, authInfo *model.SysAuthority) error
15 |
16 | SetMenuAuthority(ctx context.Context, authInfo *model.SysAuthority) error
17 | PageList(ctx context.Context, params dto.PageInfo) ([]model.SysAuthority, int64, error)
18 | }
19 |
20 | var _ Authority = &authority{}
21 |
22 | type authority struct {
23 | db *gorm.DB
24 | }
25 |
26 | func NewAuthority(db *gorm.DB) *authority {
27 | return &authority{db: db}
28 | }
29 |
30 | func (a *authority) Find(ctx context.Context, authInfo *model.SysAuthority) (*model.SysAuthority, error) {
31 | var out *model.SysAuthority
32 | return out, a.db.WithContext(ctx).Where(authInfo).Find(out).Error
33 | }
34 |
35 | func (a *authority) FindList(ctx context.Context, authInfo *model.SysAuthority) ([]*model.SysAuthority, error) {
36 | var out []*model.SysAuthority
37 | return out, a.db.WithContext(ctx).Where(&authInfo).Find(&out).Error
38 | }
39 |
40 | func (a *authority) PageList(ctx context.Context, params dto.PageInfo) ([]model.SysAuthority, int64, error) {
41 | var total int64 = 0
42 | limit := params.PageSize
43 | offset := params.PageSize * (params.Page - 1)
44 | query := a.db.WithContext(ctx)
45 | var list []model.SysAuthority
46 | // 如果有条件搜索 下方会自动创建搜索语句
47 | if params.Keyword != "" {
48 | query = query.Where("authority_name = ?", params.Keyword)
49 | }
50 | if err := query.Find(&list).Count(&total).Error; err != nil {
51 | return nil, 0, err
52 | }
53 |
54 | if err := query.Order("authority_id desc").Limit(limit).Offset(offset).Find(&list).Error; err != nil {
55 | return nil, 0, err
56 | }
57 | return list, total, nil
58 | }
59 |
60 | func (a *authority) Save(ctx context.Context, authInfo *model.SysAuthority) error {
61 | return a.db.WithContext(ctx).Create(authInfo).Error
62 | }
63 |
64 | func (a *authority) Updates(ctx context.Context, authInfo *model.SysAuthority) error {
65 | return a.db.WithContext(ctx).Updates(authInfo).Error
66 | }
67 |
68 | // SetMenuAuthority 菜单与角色绑定
69 | func (a *authority) SetMenuAuthority(ctx context.Context, authInfo *model.SysAuthority) error {
70 | var s model.SysAuthority
71 | a.db.WithContext(ctx).Preload("SysBaseMenus").First(&s, "authority_id = ?", authInfo.AuthorityId)
72 | return a.db.WithContext(ctx).Model(&s).Association("SysBaseMenus").Replace(&authInfo.SysBaseMenus)
73 | }
74 |
--------------------------------------------------------------------------------
/dao/authority/sys_authority_menus.go:
--------------------------------------------------------------------------------
1 | package authority
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type AuthorityMenu interface {
10 | FindList(ctx context.Context, in *model.SysAuthorityMenu) ([]*model.SysAuthorityMenu, error)
11 | }
12 |
13 | var _ AuthorityMenu = &authorityMenu{}
14 |
15 | type authorityMenu struct {
16 | db *gorm.DB
17 | }
18 |
19 | func NewAuthorityMenu(db *gorm.DB) *authorityMenu {
20 | return &authorityMenu{db: db}
21 | }
22 |
23 | func (a authorityMenu) FindList(ctx context.Context, in *model.SysAuthorityMenu) ([]*model.SysAuthorityMenu, error) {
24 | var out []*model.SysAuthorityMenu
25 | return out, a.db.WithContext(ctx).Where(&in).Find(&out).Error
26 | }
27 |
--------------------------------------------------------------------------------
/dao/factory.go:
--------------------------------------------------------------------------------
1 | package dao
2 |
3 | import (
4 | "gorm.io/gorm"
5 |
6 | "github.com/noovertime7/kubemanage/dao/api"
7 | "github.com/noovertime7/kubemanage/dao/authority"
8 | "github.com/noovertime7/kubemanage/dao/menu"
9 | "github.com/noovertime7/kubemanage/dao/operation"
10 | "github.com/noovertime7/kubemanage/dao/user"
11 | "github.com/noovertime7/kubemanage/dao/workflow"
12 | )
13 |
14 | // ShareDaoFactory 数据库抽象工厂 包含所有数据操作接口
15 | type ShareDaoFactory interface {
16 | GetDB() *gorm.DB
17 | WorkFlow() workflow.WorkFlowInterface
18 | User() user.User
19 | Api() api.APi
20 | Authority() authority.Authority
21 | AuthorityMenu() authority.AuthorityMenu
22 | BaseMenu() menu.BaseMenu
23 | Opera() operation.Operation
24 | }
25 |
26 | func NewShareDaoFactory(db *gorm.DB) ShareDaoFactory {
27 | return &shareDaoFactory{db: db}
28 | }
29 |
30 | var _ ShareDaoFactory = &shareDaoFactory{}
31 |
32 | type shareDaoFactory struct {
33 | db *gorm.DB
34 | }
35 |
36 | func (s *shareDaoFactory) GetDB() *gorm.DB {
37 | return s.db
38 | }
39 |
40 | func (s *shareDaoFactory) WorkFlow() workflow.WorkFlowInterface {
41 | return workflow.NewWorkFlow(s.db)
42 | }
43 |
44 | func (s *shareDaoFactory) User() user.User {
45 | return user.NewUser(s.db)
46 | }
47 |
48 | func (s *shareDaoFactory) Api() api.APi {
49 | return api.NewApi(s.db)
50 | }
51 |
52 | func (s *shareDaoFactory) Authority() authority.Authority {
53 | return authority.NewAuthority(s.db)
54 | }
55 |
56 | func (s *shareDaoFactory) AuthorityMenu() authority.AuthorityMenu {
57 | return authority.NewAuthorityMenu(s.db)
58 | }
59 |
60 | func (s *shareDaoFactory) BaseMenu() menu.BaseMenu {
61 | return menu.NewBaseMenu(s.db)
62 | }
63 |
64 | func (s *shareDaoFactory) Opera() operation.Operation {
65 | return operation.NewOperation(s.db)
66 | }
67 |
--------------------------------------------------------------------------------
/dao/menu/basemenu.go:
--------------------------------------------------------------------------------
1 | package menu
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type BaseMenu interface {
10 | Find(ctx context.Context, in *model.SysBaseMenu) (*model.SysBaseMenu, error)
11 | FindIn(ctx context.Context, in []string) ([]*model.SysBaseMenu, error)
12 | FindList(ctx context.Context, in *model.SysBaseMenu) ([]model.SysBaseMenu, error)
13 | Save(ctx context.Context, in *model.SysBaseMenu) error
14 | Updates(ctx context.Context, in *model.SysBaseMenu) error
15 | }
16 |
17 | type baseMenu struct {
18 | db *gorm.DB
19 | }
20 |
21 | func NewBaseMenu(db *gorm.DB) *baseMenu {
22 | return &baseMenu{db: db}
23 | }
24 |
25 | func (b baseMenu) Find(ctx context.Context, in *model.SysBaseMenu) (*model.SysBaseMenu, error) {
26 | var out *model.SysBaseMenu
27 | return out, b.db.WithContext(ctx).Where(in).Find(&out).Error
28 | }
29 |
30 | func (b baseMenu) FindIn(ctx context.Context, in []string) ([]*model.SysBaseMenu, error) {
31 | //做一下排序
32 | var out []*model.SysBaseMenu
33 | return out, b.db.WithContext(ctx).Where("id in (?)", in).Order("sort").Find(&out).Error
34 | }
35 |
36 | func (b baseMenu) FindList(ctx context.Context, in *model.SysBaseMenu) ([]model.SysBaseMenu, error) {
37 | var out []model.SysBaseMenu
38 | return out, b.db.WithContext(ctx).Order("sort").Where(in).Find(&out).Error
39 | }
40 |
41 | func (b baseMenu) Save(ctx context.Context, in *model.SysBaseMenu) error {
42 | return b.db.WithContext(ctx).Create(in).Error
43 | }
44 |
45 | func (b baseMenu) Updates(ctx context.Context, in *model.SysBaseMenu) error {
46 | return b.db.WithContext(ctx).Updates(in).Error
47 | }
48 |
--------------------------------------------------------------------------------
/dao/model/authorities_menus.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | "gorm.io/gorm"
7 | )
8 |
9 | func init() {
10 | RegisterInitializer(MenuAuthorityOrder, &MenuAuthority{})
11 | }
12 |
13 | type MenuAuthority struct{}
14 |
15 | func (i MenuAuthority) TableName() string {
16 | return "sys_menu_authorities"
17 | }
18 |
19 | func (i *MenuAuthority) MigrateTable(ctx context.Context, db *gorm.DB) error {
20 | //数据由gorm填充不需要手动迁移
21 | return nil
22 | }
23 |
24 | func (i *MenuAuthority) InitData(ctx context.Context, db *gorm.DB) error {
25 | var (
26 | adminRole = SysAuthorityEntities[0]
27 | userRole = SysAuthorityEntities[1]
28 | userSubRole = SysAuthorityEntities[2]
29 | err error
30 | ok bool
31 | )
32 | ok, err = i.IsInitData(ctx, db)
33 | if err != nil || ok {
34 | return err
35 | }
36 | // admin 拥有全部菜单权限
37 | if err = db.Model(&adminRole).Association("SysBaseMenus").Append(SysBaseMenuEntities); err != nil {
38 | return err
39 | }
40 |
41 | // userRole cmdb菜单
42 | menu8881 := SysBaseMenuEntities[5:7]
43 | menu8881 = append(menu8881, SysBaseMenuEntities[0])
44 | menu8881 = append(menu8881, SysBaseMenuEntities[1])
45 | if err = db.Model(&userRole).Association("SysBaseMenus").Replace(menu8881); err != nil {
46 | return err
47 | }
48 |
49 | // userSubRole
50 | if err = db.Model(&userSubRole).Association("SysBaseMenus").Replace(SysBaseMenuEntities[:6]); err != nil {
51 | return err
52 | }
53 | if err = db.Model(&userSubRole).Association("SysBaseMenus").Append(SysBaseMenuEntities[5:6]); err != nil {
54 | return err
55 | }
56 | return nil
57 | }
58 |
59 | func (i *MenuAuthority) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
60 | auth := &SysAuthority{}
61 | if err := db.WithContext(ctx).Model(auth).Where("authority_id = ?", pkg.AdminDefaultAuth).Preload("SysBaseMenus").Find(auth).Error; err != nil {
62 | return false, err
63 | }
64 | return len(auth.SysBaseMenus) > 0, nil
65 | }
66 |
67 | func (i *MenuAuthority) TableCreated(ctx context.Context, db *gorm.DB) bool {
68 | return false // always replace
69 | }
70 |
--------------------------------------------------------------------------------
/dao/model/authority.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "github.com/pkg/errors"
6 | "gorm.io/gorm"
7 | )
8 |
9 | func init() {
10 | RegisterInitializer(SysAuthorityOrder, &SysAuthority{})
11 | }
12 |
13 | type SysAuthority struct {
14 | CommonModel
15 | AuthorityId uint `json:"authorityId" gorm:"not null;unique;primary_key;comment:角色ID;size:90"` // 角色ID
16 | AuthorityName string `json:"authorityName" gorm:"comment:角色名"` // 角色名
17 | ParentId uint `json:"parentId" gorm:"comment:父角色ID"` // 父角色ID
18 | DataAuthorityId []*SysAuthority `json:"dataAuthorityId" gorm:"many2many:sys_data_authority_id;"`
19 | Children []SysAuthority `json:"children" gorm:"-"`
20 | SysBaseMenus []SysBaseMenu `json:"menus" gorm:"many2many:sys_authority_menus;"`
21 | Users []SysUser `json:"-" gorm:"many2many:sys_user_authority;"`
22 | DefaultRouter string `json:"defaultRouter" gorm:"comment:默认菜单;default:dashboard"` // 默认菜单(默认dashboard)
23 | }
24 |
25 | func (s *SysAuthority) MigrateTable(ctx context.Context, db *gorm.DB) error {
26 | return db.WithContext(ctx).AutoMigrate(&s)
27 | }
28 |
29 | func (s *SysAuthority) InitData(ctx context.Context, db *gorm.DB) error {
30 | ok, err := s.IsInitData(ctx, db)
31 | if err != nil || ok {
32 | return err
33 | }
34 | if err := db.Model(&SysAuthorityEntities[0]).Association("DataAuthorityId").Replace(
35 | []*SysAuthority{
36 | {AuthorityId: 111},
37 | {AuthorityId: 222},
38 | {AuthorityId: 2221},
39 | }); err != nil {
40 | return errors.Wrapf(err, "%s表数据初始化失败!",
41 | db.Model(&SysAuthorityEntities[0]).Association("DataAuthorityId").Relationship.JoinTable.Name)
42 | }
43 | if err := db.Model(&SysAuthorityEntities[1]).Association("DataAuthorityId").Replace(
44 | []*SysAuthority{
45 | {AuthorityId: 222},
46 | {AuthorityId: 2221},
47 | }); err != nil {
48 | return errors.Wrapf(err, "%s表数据初始化失败!",
49 | db.Model(&SysAuthorityEntities[1]).Association("DataAuthorityId").Relationship.JoinTable.Name)
50 | }
51 | return nil
52 | }
53 |
54 | func (s *SysAuthority) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
55 | var out *SysAuthority
56 | if err := db.WithContext(ctx).Where("authority_id = '111' ").Find(&out).Error; err != nil {
57 | return false, nil
58 | }
59 | return out.AuthorityId != 0, nil
60 | }
61 |
62 | func (s *SysAuthority) TableCreated(ctx context.Context, db *gorm.DB) bool {
63 | return db.WithContext(ctx).Migrator().HasTable(&s)
64 | }
65 |
66 | func (*SysAuthority) TableName() string {
67 | return "sys_authorities"
68 | }
69 |
--------------------------------------------------------------------------------
/dao/model/casbin.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "github.com/pkg/errors"
6 | "gorm.io/gorm"
7 |
8 | adapter "github.com/casbin/gorm-adapter/v3"
9 | )
10 |
11 | func init() {
12 | RegisterInitializer(CasbinInitOrder, &casbinDateBase{})
13 | }
14 |
15 | type casbinDateBase struct{}
16 |
17 | func (c casbinDateBase) TableName() string {
18 | var entity adapter.CasbinRule
19 | return entity.TableName()
20 | }
21 |
22 | func (c casbinDateBase) MigrateTable(ctx context.Context, db *gorm.DB) error {
23 | return db.WithContext(ctx).AutoMigrate(&adapter.CasbinRule{})
24 | }
25 |
26 | func (c casbinDateBase) InitData(ctx context.Context, db *gorm.DB) error {
27 | ok, err := c.IsInitData(ctx, db)
28 | if err != nil || ok {
29 | return err
30 | }
31 | return db.WithContext(ctx).Create(CasbinApi).Error
32 | }
33 |
34 | func (c casbinDateBase) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
35 | // TODO 管理员用户判断登陆接口是否具有权限
36 | if errors.Is(gorm.ErrRecordNotFound, db.WithContext(ctx).Where(adapter.CasbinRule{Ptype: "p", V0: "222", V1: "/api/user/login", V2: "POST"}).
37 | First(&adapter.CasbinRule{}).Error) { // 判断是否存在数据
38 | return false, nil
39 | }
40 | return true, nil
41 | }
42 |
43 | func (c casbinDateBase) TableCreated(ctx context.Context, db *gorm.DB) bool {
44 | return db.WithContext(ctx).Migrator().HasTable(&adapter.CasbinRule{})
45 | }
46 |
--------------------------------------------------------------------------------
/dao/model/common.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "gorm.io/gorm"
5 | "time"
6 | )
7 |
8 | type CommonModel struct {
9 | CreatedAt time.Time `json:"created_at" gorm:"column:created_at"`
10 | UpdatedAt time.Time `json:"updated_at" gorm:"column:updated_at"`
11 | DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
12 | }
13 |
--------------------------------------------------------------------------------
/dao/model/db_initializer.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "gorm.io/gorm"
6 | )
7 |
8 | // DBInitializer 用于初始化数据表与数据
9 | type DBInitializer interface {
10 | TableName() string
11 | MigrateTable(ctx context.Context, db *gorm.DB) error
12 | InitData(ctx context.Context, db *gorm.DB) error
13 | IsInitData(ctx context.Context, db *gorm.DB) (bool, error)
14 | TableCreated(ctx context.Context, db *gorm.DB) bool
15 | }
16 |
17 | var InitializerList []*OrderedInitializer
18 |
19 | // OrderedInitializer 组合一个顺序字段,以供排序
20 | type OrderedInitializer struct {
21 | Order int
22 | DBInitializer
23 | }
24 |
25 | func RegisterInitializer(order int, c DBInitializer) {
26 | InitializerList = append(InitializerList, &OrderedInitializer{
27 | Order: order,
28 | DBInitializer: c,
29 | })
30 | InitializerList = bubbleSort(InitializerList)
31 | }
32 |
33 | // 冒泡排序,根据order选择初始化顺序
34 | func bubbleSort(s []*OrderedInitializer) []*OrderedInitializer {
35 | n := len(s)
36 | for i := 0; i < n-1; i++ {
37 | for j := 0; j < n-i-1; j++ {
38 | if s[j].Order > s[j+1].Order {
39 | s[j], s[j+1] = s[j+1], s[j]
40 | }
41 | }
42 | }
43 | return s
44 | }
45 |
--------------------------------------------------------------------------------
/dao/model/operation.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "time"
6 |
7 | "gorm.io/gorm"
8 | )
9 |
10 | func init() {
11 | RegisterInitializer(OperatorationOrder, &SysOperationRecord{})
12 | }
13 |
14 | type SysOperationRecord struct {
15 | ID int `gorm:"column:id;primary_key;AUTO_INCREMENT;not null" json:"id"`
16 | Ip string `json:"ip" form:"ip" gorm:"column:ip;comment:请求ip"` // 请求ip
17 | Method string `json:"method" form:"method" gorm:"column:method;comment:请求方法"` // 请求方法
18 | Path string `json:"path" form:"path" gorm:"column:path;comment:请求路径"` // 请求路径
19 | Status int `json:"status" form:"status" gorm:"column:status;comment:请求状态"` // 请求状态
20 | Latency time.Duration `json:"latency" form:"latency" gorm:"column:latency;comment:延迟" swaggertype:"string"` // 延迟
21 | Agent string `json:"agent" form:"agent" gorm:"column:agent;comment:代理"` // 代理
22 | ErrorMessage string `json:"error_message" form:"error_message" gorm:"column:error_message;comment:错误信息"` // 错误信息
23 | Body string `json:"body" form:"body" gorm:"type:text;column:body;comment:请求Body"` // 请求Body
24 | Resp string `json:"resp" form:"resp" gorm:"type:text;column:resp;comment:响应Body"` // 响应Body
25 | UserID int `json:"user_id" form:"user_id" gorm:"column:user_id;comment:用户id"` // 用户id
26 | User SysUser `json:"user"`
27 | CommonModel
28 | }
29 |
30 | func (s *SysOperationRecord) MigrateTable(ctx context.Context, db *gorm.DB) error {
31 | return db.WithContext(ctx).AutoMigrate(s)
32 | }
33 |
34 | func (s *SysOperationRecord) InitData(ctx context.Context, db *gorm.DB) error {
35 | // 审计表,不需要初始化数据
36 | return nil
37 | }
38 |
39 | func (s *SysOperationRecord) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
40 | return true, nil
41 | }
42 |
43 | func (s *SysOperationRecord) TableCreated(ctx context.Context, db *gorm.DB) bool {
44 | return db.WithContext(ctx).Migrator().HasTable(&s)
45 | }
46 |
47 | func (s *SysOperationRecord) TableName() string {
48 | return "sys_operation_record"
49 | }
50 |
--------------------------------------------------------------------------------
/dao/model/sys_api.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "gorm.io/gorm"
6 | )
7 |
8 | func init() {
9 | RegisterInitializer(SysApisInitOrder, &SysApi{})
10 | }
11 |
12 | type SysApi struct {
13 | ID int `gorm:"column:id;primary_key;AUTO_INCREMENT;not null" json:"id"`
14 | Path string `json:"path" gorm:"comment:api路径"` // api路径
15 | Description string `json:"description" gorm:"comment:api中文描述"` // api中文描述
16 | ApiGroup string `json:"apiGroup" gorm:"comment:api组"` // api组
17 | Method string `json:"method" gorm:"default:POST;comment:方法"` // 方法:创建POST(默认)|查看GET|更新PUT|删除DELETE
18 | CommonModel
19 | }
20 |
21 | func (a *SysApi) MigrateTable(ctx context.Context, db *gorm.DB) error {
22 | return db.WithContext(ctx).AutoMigrate(a)
23 | }
24 |
25 | func (a *SysApi) InitData(ctx context.Context, db *gorm.DB) error {
26 | ok, err := a.IsInitData(ctx, db)
27 | if err != nil || ok {
28 | return err
29 | }
30 | return db.WithContext(ctx).Create(SysApis).Error
31 | }
32 |
33 | func (a *SysApi) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
34 | var out *SysApi
35 | // TODO 验证方式统一优化
36 | if err := db.WithContext(ctx).Where("path = '/api/user/login' ").Find(&out).Error; err != nil {
37 | return false, nil
38 | }
39 | return out.ID != 0, nil
40 | }
41 |
42 | func (a *SysApi) TableCreated(ctx context.Context, db *gorm.DB) bool {
43 | return db.WithContext(ctx).Migrator().HasTable(a)
44 | }
45 |
46 | func (*SysApi) TableName() string {
47 | return "sys_apis"
48 | }
49 |
--------------------------------------------------------------------------------
/dao/model/sys_authority_menu.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | type SysMenu struct {
4 | SysBaseMenu
5 | MenuId string `json:"menuId" gorm:"comment:菜单ID"`
6 | AuthorityId uint `json:"-" gorm:"comment:角色ID"`
7 | Children []SysMenu `json:"children" gorm:"-"`
8 | }
9 |
10 | type SysAuthorityMenu struct {
11 | MenuId string `json:"menuId" gorm:"comment:菜单ID;column:sys_base_menu_id"`
12 | AuthorityId string `json:"-" gorm:"comment:角色ID;column:sys_authority_authority_id"`
13 | }
14 |
15 | func (s SysAuthorityMenu) TableName() string {
16 | return "sys_authority_menus"
17 | }
18 |
--------------------------------------------------------------------------------
/dao/model/sys_base_menu.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "github.com/pkg/errors"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type SysBaseMenu struct {
10 | ID int `gorm:"column:id;primary_key;AUTO_INCREMENT;not null" json:"id"`
11 | MenuLevel uint `json:"-"`
12 | ParentId string `json:"parentId" gorm:"comment:父菜单ID"` // 父菜单ID
13 | Path string `json:"path" gorm:"comment:路由path"` // 路由path
14 | Name string `json:"name" gorm:"comment:路由name"` // 路由name
15 | Hidden bool `json:"hidden" gorm:"comment:是否在列表隐藏"` // 是否在列表隐藏
16 | Disabled bool `json:"disabled" gorm:"comment:是否禁止修改菜单"` // 是否在列表隐藏
17 | Sort int `json:"sort" gorm:"comment:排序标记"` // 排序标记
18 | Children []SysBaseMenu `json:"children" gorm:"-"`
19 | Meta `json:"meta" gorm:"embedded;comment:附加属性"` // 附加属性
20 | SysAuthoritys []SysAuthority `json:"authoritys" gorm:"many2many:sys_authority_menus;"`
21 | CommonModel
22 | }
23 |
24 | type Meta struct {
25 | ActiveName string `json:"activeName" gorm:"comment:高亮菜单"`
26 | KeepAlive bool `json:"keepAlive" gorm:"comment:是否缓存"` // 是否缓存
27 | Title string `json:"title" gorm:"comment:菜单名"` // 菜单名
28 | Icon string `json:"icon" gorm:"comment:菜单图标"` // 菜单图标
29 | CloseTab bool `json:"closeTab" gorm:"comment:自动关闭tab"` // 自动关闭tab
30 | }
31 |
32 | func init() {
33 | RegisterInitializer(SysBaseMenuOrder, &SysBaseMenu{})
34 | }
35 |
36 | func (m *SysBaseMenu) MigrateTable(ctx context.Context, db *gorm.DB) error {
37 | return db.WithContext(ctx).AutoMigrate(&m)
38 | }
39 |
40 | func (m *SysBaseMenu) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
41 | var out *SysBaseMenu
42 | if err := db.WithContext(ctx).Where("path = 'dashboard' ").Find(&out).Error; err != nil {
43 | return false, nil
44 | }
45 | return out.ID != 0, nil
46 | }
47 |
48 | func (m *SysBaseMenu) InitData(ctx context.Context, db *gorm.DB) error {
49 | ok, err := m.IsInitData(ctx, db)
50 | if err != nil || ok {
51 | return err
52 | }
53 | if !ok {
54 | if err := db.WithContext(ctx).Create(&SysBaseMenuEntities).Error; err != nil {
55 | menu := SysBaseMenu{}
56 | return errors.Wrap(err, menu.TableName()+"表数据初始化失败!")
57 | }
58 | }
59 | return nil
60 | }
61 |
62 | func (m *SysBaseMenu) TableCreated(ctx context.Context, db *gorm.DB) bool {
63 | return db.WithContext(ctx).Migrator().HasTable(&m)
64 | }
65 |
66 | func (*SysBaseMenu) TableName() string {
67 | return "sys_base_menus"
68 | }
69 |
--------------------------------------------------------------------------------
/dao/model/user.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "database/sql"
6 | uuid "github.com/satori/go.uuid"
7 | "gorm.io/gorm"
8 | )
9 |
10 | type SysUser struct {
11 | ID int `gorm:"column:id;primary_key;AUTO_INCREMENT;not null" json:"id"`
12 | UUID uuid.UUID `json:"uuid" gorm:"index;comment:用户UUID"` // 用户UUID
13 | UserName string `json:"userName" gorm:"index;comment:用户登录名"` // 用户登录名
14 | Password string `json:"-" gorm:"comment:用户登录密码"` // 用户登录密码
15 | NickName string `json:"nickName" gorm:"default:系统用户;comment:用户昵称"` // 用户昵称
16 | SideMode string `json:"sideMode" gorm:"default:dark;comment:用户侧边主题"` // 用户侧边主题
17 | Avatar string `json:"avatar" gorm:"default:https://qmplusimg.henrongyi.top/gva_header.jpg;comment:用户头像"` // 用户头像
18 | BaseColor string `json:"baseColor" gorm:"default:#fff;comment:基础颜色"` // 基础颜色
19 | ActiveColor string `json:"activeColor" gorm:"default:#1890ff;comment:活跃颜色"` // 活跃颜色
20 | AuthorityId uint `json:"authorityId" gorm:"default:2222;comment:用户角色ID"` // 用户角色ID
21 | Authority SysAuthority `json:"authority" gorm:"foreignKey:AuthorityId;references:AuthorityId;comment:用户角色"`
22 | Authorities []SysAuthority `json:"authorities" gorm:"many2many:sys_user_authority;"`
23 | Phone string `json:"phone" gorm:"comment:用户手机号"` // 用户手机号
24 | Email string `json:"email" gorm:"comment:用户邮箱"` // 用户邮箱
25 | Enable int `json:"enable" gorm:"default:1;comment:用户是否被冻结 1正常 2冻结"` //用户是否被冻结 1正常 2冻结
26 | Status sql.NullInt64 `gorm:"column:status;type:int(11);comment:0离线;1在线" json:"status"`
27 | CommonModel
28 | }
29 |
30 | func init() {
31 | RegisterInitializer(SysUserOrder, &SysUser{})
32 | }
33 |
34 | func (u *SysUser) TableName() string {
35 | return "sys_users"
36 | }
37 |
38 | func (u *SysUser) InitData(ctx context.Context, db *gorm.DB) error {
39 | ok, err := u.IsInitData(ctx, db)
40 | if err != nil || ok {
41 | return err
42 | }
43 | if err := db.WithContext(ctx).Create(SysUserEntities).Error; err != nil {
44 | return err
45 | }
46 | //管理员用户
47 | if err := db.Model(&SysUserEntities[0]).Association("Authorities").Replace(SysAuthorityEntities); err != nil {
48 | return err
49 | }
50 | //普通用户
51 | if err := db.Model(&SysUserEntities[1]).Association("Authorities").Replace(SysAuthorityEntities[:1]); err != nil {
52 | return err
53 | }
54 | return nil
55 | }
56 |
57 | // IsInitData 判断是否admin初始化成功
58 | func (u *SysUser) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
59 | adminOk, err := u.isAdminInit(ctx, db)
60 | if err != nil {
61 | return false, nil
62 | }
63 | return adminOk, nil
64 | }
65 |
66 | func (u *SysUser) isAdminInit(ctx context.Context, db *gorm.DB) (bool, error) {
67 | var out *SysUser
68 | if err := db.WithContext(ctx).Where("user_name = 'admin' ").Find(&out).Error; err != nil {
69 | return false, err
70 | }
71 | return out.ID != 0, nil
72 | }
73 |
74 | func (u *SysUser) MigrateTable(ctx context.Context, db *gorm.DB) error {
75 | return db.WithContext(ctx).AutoMigrate(&u)
76 | }
77 |
78 | func (u *SysUser) TableCreated(ctx context.Context, db *gorm.DB) bool {
79 | return db.WithContext(ctx).Migrator().HasTable(u)
80 | }
81 |
--------------------------------------------------------------------------------
/dao/model/workflow.go:
--------------------------------------------------------------------------------
1 | package model
2 |
3 | import (
4 | "context"
5 | "gorm.io/gorm"
6 | )
7 |
8 | func init() {
9 | RegisterInitializer(WorkFlowOrder, &Workflow{})
10 | }
11 |
12 | type Workflow struct {
13 | ID int `gorm:"column:id;primary_key;AUTO_INCREMENT;not null" json:"id"`
14 | Name string `json:"name" gorm:"column:name"`
15 | NameSpace string `json:"namespace" gorm:"column:namespace"`
16 | Replicas int32 `json:"replicas" gorm:"column:replicas"`
17 | Deployment string `json:"deployment" gorm:"column:deployment"`
18 | Service string `json:"service" gorm:"column:service"`
19 | Ingress string `json:"ingress" gorm:"column:ingress"`
20 | ServiceType string `json:"service_type" gorm:"column:service_type"`
21 | CommonModel
22 | }
23 |
24 | func (w *Workflow) MigrateTable(ctx context.Context, db *gorm.DB) error {
25 | return db.WithContext(ctx).AutoMigrate(&w)
26 | }
27 |
28 | func (w *Workflow) IsInitData(ctx context.Context, db *gorm.DB) (bool, error) {
29 | return true, nil
30 | }
31 |
32 | func (w *Workflow) InitData(ctx context.Context, db *gorm.DB) error {
33 | return nil
34 | }
35 |
36 | func (w *Workflow) TableCreated(ctx context.Context, db *gorm.DB) bool {
37 | return db.WithContext(ctx).Migrator().HasTable(w)
38 | }
39 |
40 | func (w *Workflow) TableName() string {
41 | return "t_workflow"
42 | }
43 |
44 | func GetWorkflowTableName() string {
45 | temp := &Workflow{}
46 | return temp.TableName()
47 | }
48 |
--------------------------------------------------------------------------------
/dao/operation/operation.go:
--------------------------------------------------------------------------------
1 | package operation
2 |
3 | import (
4 | "context"
5 |
6 | "gorm.io/gorm"
7 |
8 | "github.com/noovertime7/kubemanage/dao/model"
9 | "github.com/noovertime7/kubemanage/dto"
10 | )
11 |
12 | type Operation interface {
13 | Find(ctx context.Context, in *model.SysOperationRecord) (*model.SysOperationRecord, error)
14 | PageList(ctx context.Context, params *dto.OperationListInput) ([]*model.SysOperationRecord, int64, error)
15 | Save(ctx context.Context, in *model.SysOperationRecord) error
16 | Delete(ctx context.Context, in *model.SysOperationRecord) error
17 | DeleteList(ctx context.Context, in []int) error
18 | }
19 |
20 | type operation struct {
21 | db *gorm.DB
22 | }
23 |
24 | func (o *operation) Find(ctx context.Context, in *model.SysOperationRecord) (*model.SysOperationRecord, error) {
25 | out := &model.SysOperationRecord{}
26 | return out, o.db.WithContext(ctx).Where(in).Find(&out).Error
27 | }
28 |
29 | func (o *operation) Save(ctx context.Context, in *model.SysOperationRecord) error {
30 | return o.db.WithContext(ctx).Create(in).Error
31 | }
32 |
33 | func (o *operation) Delete(ctx context.Context, in *model.SysOperationRecord) error {
34 | return o.db.WithContext(ctx).Delete(in).Error
35 | }
36 |
37 | func (o *operation) DeleteList(ctx context.Context, in []int) error {
38 | return o.db.WithContext(ctx).Delete(&[]model.SysOperationRecord{}, "id in (?)", in).Error
39 | }
40 |
41 | func NewOperation(db *gorm.DB) *operation {
42 | return &operation{db: db}
43 | }
44 |
45 | func (o *operation) PageList(ctx context.Context, params *dto.OperationListInput) ([]*model.SysOperationRecord, int64, error) {
46 | var total int64 = 0
47 | limit := params.PageSize
48 | offset := params.PageSize * (params.Page - 1)
49 | query := o.db.WithContext(ctx)
50 | var list []*model.SysOperationRecord
51 | // 如果有条件搜索 下方会自动创建搜索语句
52 | if params.Method != "" {
53 | query = query.Where("method = ?", params.Method)
54 | }
55 | if params.Path != "" {
56 | query = query.Where("path = ?", params.Path)
57 | }
58 | if params.Status != 0 {
59 | query = query.Where("status = ?", params.Status)
60 | }
61 |
62 | if err := query.Find(&list).Count(&total).Error; err != nil {
63 | return nil, 0, err
64 | }
65 |
66 | if err := query.Order("id desc").Limit(limit).Offset(offset).Preload("User").Find(&list).Error; err != nil {
67 | return nil, 0, err
68 | }
69 | return list, total, nil
70 | }
71 |
--------------------------------------------------------------------------------
/dao/user/user.go:
--------------------------------------------------------------------------------
1 | package user
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "github.com/pkg/errors"
7 | "gorm.io/gorm"
8 | )
9 |
10 | type User interface {
11 | Find(ctx context.Context, userInfo *model.SysUser) (*model.SysUser, error)
12 | Save(ctx context.Context, userInfo *model.SysUser) error
13 | Updates(ctx context.Context, userInfo *model.SysUser) error
14 | Delete(ctx context.Context, userInfo *model.SysUser) error
15 | }
16 |
17 | var _ User = &user{}
18 |
19 | type user struct {
20 | db *gorm.DB
21 | }
22 |
23 | func NewUser(db *gorm.DB) *user {
24 | return &user{db: db}
25 | }
26 |
27 | func (u *user) Find(ctx context.Context, userInfo *model.SysUser) (*model.SysUser, error) {
28 | user := &model.SysUser{}
29 | if err := u.db.WithContext(ctx).Preload("Authorities").Preload("Authority").Where(userInfo).Find(user).Error; err != nil {
30 | if err == gorm.ErrRecordNotFound {
31 | return nil, gorm.ErrRecordNotFound
32 | }
33 | return nil, err
34 | }
35 | return user, nil
36 | }
37 |
38 | func (u *user) Save(ctx context.Context, userInfo *model.SysUser) error {
39 | return u.db.WithContext(ctx).Save(userInfo).Error
40 | }
41 |
42 | func (u *user) Updates(ctx context.Context, userInfo *model.SysUser) error {
43 | if userInfo.ID == 0 {
44 | return errors.New("id not set")
45 | }
46 | return u.db.WithContext(ctx).Updates(userInfo).Error
47 | }
48 |
49 | func (u *user) Delete(ctx context.Context, userInfo *model.SysUser) error {
50 | return u.db.WithContext(ctx).Delete(userInfo).Error
51 | }
52 |
--------------------------------------------------------------------------------
/dao/workflow/workflow.go:
--------------------------------------------------------------------------------
1 | package workflow
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "github.com/noovertime7/kubemanage/dto/kubeDto"
7 | "github.com/pkg/errors"
8 | "gorm.io/gorm"
9 | "time"
10 | )
11 |
12 | type WorkFlowInterface interface {
13 | Save(ctx context.Context, obj *model.Workflow) error
14 | Updates(ctx context.Context, obj *model.Workflow) error
15 | Find(ctx context.Context, id int) (*model.Workflow, error)
16 | FindList(ctx context.Context, search *model.Workflow) ([]*model.Workflow, error)
17 | PageList(ctx context.Context, params *kubeDto.WorkFlowListInput) ([]*model.Workflow, int, error)
18 | Delete(ctx context.Context, wid int) error
19 | }
20 |
21 | type workflow struct {
22 | db *gorm.DB
23 | }
24 |
25 | func NewWorkFlow(db *gorm.DB) WorkFlowInterface {
26 | return &workflow{db: db}
27 | }
28 |
29 | func (w *workflow) PageList(ctx context.Context, params *kubeDto.WorkFlowListInput) ([]*model.Workflow, int, error) {
30 | var total int64 = 0
31 | var list []*model.Workflow
32 | offset := (params.Page - 1) * params.Limit
33 | query := w.db.WithContext(ctx).Table(model.GetWorkflowTableName())
34 | query.Find(&list).Count(&total)
35 | if params.FilterName != "" {
36 | query = query.Where("( name like ?)", "%"+params.FilterName+"%")
37 | }
38 | if err := query.Limit(params.Limit).Offset(offset).Order("id desc").Find(&list).Error; err != nil && err != gorm.ErrRecordNotFound {
39 | return nil, 0, err
40 | }
41 | return list, int(total), nil
42 | }
43 |
44 | func (w *workflow) Save(ctx context.Context, obj *model.Workflow) error {
45 | now := time.Now()
46 | obj.UpdatedAt = now
47 | return w.db.WithContext(ctx).Save(obj).Error
48 | }
49 |
50 | func (w *workflow) Updates(ctx context.Context, obj *model.Workflow) error {
51 | if obj.ID == 0 {
52 | return errors.New("id no set")
53 | }
54 | return w.db.WithContext(ctx).Updates(obj).Error
55 | }
56 |
57 | func (w *workflow) Find(ctx context.Context, id int) (*model.Workflow, error) {
58 | out := &model.Workflow{}
59 | return out, w.db.WithContext(ctx).Where("id = ?", id).First(out).Error
60 | }
61 |
62 | func (w *workflow) FindList(ctx context.Context, search *model.Workflow) ([]*model.Workflow, error) {
63 | var res []*model.Workflow
64 | return res, w.db.WithContext(ctx).Where(&search).Find(&res).Error
65 | }
66 |
67 | func (w *workflow) Delete(ctx context.Context, wid int) error {
68 | return w.db.WithContext(ctx).Where("id = ?", wid).Delete(&model.Workflow{}).Error
69 | }
70 |
--------------------------------------------------------------------------------
/dto/authority.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import "github.com/noovertime7/kubemanage/dao/model"
4 |
5 | type AuthorityList struct {
6 | PageInfo
7 | Total int64 `json:"total"`
8 | AuthorityListItem []model.SysAuthority `json:"list"`
9 | }
10 |
--------------------------------------------------------------------------------
/dto/casbin.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | // CasbinInfo Casbin info structure
9 | type CasbinInfo struct {
10 | Path string `form:"path" json:"path"` // 路径
11 | Method string ` form:"method" json:"method"` // 方法
12 | }
13 |
14 | // UpdateCasbinInput 通过角色id更改接口权限
15 | type UpdateCasbinInput struct {
16 | AuthorityId uint `form:"authorityId" json:"authorityId"` // 权限id
17 | CasbinInfo []CasbinInfo `json:"casbinInfos"`
18 | }
19 |
20 | // CasbinInReceive Casbin structure for input parameters
21 | type CasbinInReceive struct {
22 | AuthorityId uint `form:"authorityId" json:"authorityId"` // 权限id
23 | }
24 |
25 | // BindingValidParams 绑定并校验参数
26 | func (a *CasbinInReceive) BindingValidParams(ctx *gin.Context) error {
27 | return pkg.DefaultGetValidParams(ctx, a)
28 | }
29 |
30 | // BindingValidParams 绑定并校验参数
31 | func (a *UpdateCasbinInput) BindingValidParams(ctx *gin.Context) error {
32 | return pkg.DefaultGetValidParams(ctx, a)
33 | }
34 |
--------------------------------------------------------------------------------
/dto/common.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | // Empty 用于swag生成不需要传参的api
9 | type Empty struct{}
10 |
11 | // PageInfo Paging common input parameter structure
12 | type PageInfo struct {
13 | Page int `json:"page" form:"page"` // 页码
14 | PageSize int `json:"pageSize" form:"pageSize"` // 每页大小
15 | Keyword string `json:"keyword" form:"keyword"` //关键字
16 | }
17 |
18 | type IdsReq struct {
19 | Ids []int `json:"ids" form:"ids"`
20 | }
21 |
22 | // BindingValidParams 绑定并校验参数
23 | func (a *IdsReq) BindingValidParams(ctx *gin.Context) error {
24 | return pkg.DefaultGetValidParams(ctx, a)
25 | }
26 |
27 | func (a *PageInfo) BindingValidParams(ctx *gin.Context) error {
28 | return pkg.DefaultGetValidParams(ctx, a)
29 | }
30 |
--------------------------------------------------------------------------------
/dto/kubeDto/configmap.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type ConfigmapNameNS struct {
9 | Name string `json:"name" form:"name" comment:"配置卷名称" validate:"required"`
10 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
11 | }
12 |
13 | type ConfigmapUpdateInput struct {
14 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
15 | Content string `json:"content" form:"content" validate:"required" comment:"更新内容"`
16 | }
17 |
18 | type ConfigmapListInput struct {
19 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
20 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
21 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
22 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
23 | }
24 |
25 | func (params *ConfigmapNameNS) BindingValidParams(c *gin.Context) error {
26 | return pkg.DefaultGetValidParams(c, params)
27 | }
28 |
29 | func (params *ConfigmapUpdateInput) BindingValidParams(c *gin.Context) error {
30 | return pkg.DefaultGetValidParams(c, params)
31 | }
32 |
33 | func (params *ConfigmapListInput) BindingValidParams(c *gin.Context) error {
34 | return pkg.DefaultGetValidParams(c, params)
35 | }
36 |
--------------------------------------------------------------------------------
/dto/kubeDto/daemonset.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type DaemonSetNameNS struct {
9 | Name string `json:"name" form:"name" comment:"有状态控制器名称" validate:"required"`
10 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
11 | }
12 |
13 | type DaemonSetUpdateInput struct {
14 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
15 | Content string `json:"content" validate:"required" comment:"更新内容"`
16 | }
17 |
18 | type DaemonSetListInput struct {
19 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
20 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
21 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
22 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
23 | }
24 |
25 | func (params *DaemonSetNameNS) BindingValidParams(c *gin.Context) error {
26 | return pkg.DefaultGetValidParams(c, params)
27 | }
28 |
29 | func (params *DaemonSetUpdateInput) BindingValidParams(c *gin.Context) error {
30 | return pkg.DefaultGetValidParams(c, params)
31 | }
32 |
33 | func (params *DaemonSetListInput) BindingValidParams(c *gin.Context) error {
34 | return pkg.DefaultGetValidParams(c, params)
35 | }
36 |
--------------------------------------------------------------------------------
/dto/kubeDto/deployment.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type DeploymentNameNS struct {
9 | Name string `json:"deployment_name" form:"deployment_name" comment:"无状态控制器名称" validate:"required"`
10 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
11 | }
12 |
13 | type DeployCreateInput struct {
14 | //DeploymentNameNS
15 | Name string `json:"name" form:"name" comment:"无状态控制器名称" validate:"required"`
16 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
17 | Replicas int32 `json:"replicas" validate:"required" comment:"副本数"`
18 | Image string `json:"image" validate:"required" comment:"镜像名"`
19 | Labels map[string]string `json:"label" validate:"" comment:"标签"`
20 | Cpu string `json:"cpu" validate:"" comment:"Cpu限制"`
21 | Memory string `json:"memory" validate:"" comment:"内存限制"`
22 | ContainerPort int32 `json:"container_port" validate:"" comment:"容器端口"`
23 | HealthCheck bool `json:"health_check" validate:"" comment:"健康检查开关"`
24 | HealthPath string `json:"health_path" validate:"" comment:"Http健康检查路径"`
25 | }
26 |
27 | type UpdateDeployInput struct {
28 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
29 | Content string `json:"content" form:"content" validate:"required" comment:"更新内容"`
30 | }
31 |
32 | type DeployScaleInput struct {
33 | Name string `json:"deployment_name" form:"deployment_name" comment:"无状态控制器名称" validate:"required"`
34 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
35 | ScaleNum int `json:"scale_num" form:"scale_num" comment:"期望副本数" validate:"required"`
36 | }
37 |
38 | type DeployListInput struct {
39 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
40 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
41 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
42 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
43 | }
44 |
45 | func (params *DeployListInput) BindingValidParams(c *gin.Context) error {
46 | return pkg.DefaultGetValidParams(c, params)
47 | }
48 |
49 | func (params *UpdateDeployInput) BindingValidParams(c *gin.Context) error {
50 | return pkg.DefaultGetValidParams(c, params)
51 | }
52 |
53 | func (params *DeployCreateInput) BindingValidParams(c *gin.Context) error {
54 | return pkg.DefaultGetValidParams(c, params)
55 | }
56 |
57 | func (params *DeployScaleInput) BindingValidParams(c *gin.Context) error {
58 | return pkg.DefaultGetValidParams(c, params)
59 | }
60 |
61 | func (params *DeploymentNameNS) BindingValidParams(c *gin.Context) error {
62 | return pkg.DefaultGetValidParams(c, params)
63 | }
64 |
--------------------------------------------------------------------------------
/dto/kubeDto/ingress.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | nwV1 "k8s.io/api/networking/v1"
7 | )
8 |
9 | type IngressCreteInput struct {
10 | Name string `json:"name"`
11 | NameSpace string `json:"namespace"`
12 | Label map[string]string `json:"label"`
13 | Hosts map[string][]*HttpPath `json:"hosts"`
14 | }
15 |
16 | type HttpPath struct {
17 | Path string `json:"path"`
18 | PathType nwV1.PathType `json:"path_type"`
19 | ServiceName string `json:"service_name"`
20 | ServicePort int32 `json:"service_port"`
21 | }
22 |
23 | type IngressNameNS struct {
24 | Name string `json:"name" form:"name" comment:"服务名称" validate:"required"`
25 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
26 | }
27 |
28 | type IngressUpdateInput struct {
29 | Content string `json:"content" form:"content" validate:"required" comment:"更新内容"`
30 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
31 | }
32 |
33 | type IngressListInput struct {
34 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
35 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
36 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
37 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
38 | }
39 |
40 | func (params *IngressCreteInput) BindingValidParams(c *gin.Context) error {
41 | return pkg.DefaultGetValidParams(c, params)
42 | }
43 |
44 | func (params *IngressNameNS) BindingValidParams(c *gin.Context) error {
45 | return pkg.DefaultGetValidParams(c, params)
46 | }
47 |
48 | func (params *IngressUpdateInput) BindingValidParams(c *gin.Context) error {
49 | return pkg.DefaultGetValidParams(c, params)
50 | }
51 |
52 | func (params *IngressListInput) BindingValidParams(c *gin.Context) error {
53 | return pkg.DefaultGetValidParams(c, params)
54 | }
55 |
--------------------------------------------------------------------------------
/dto/kubeDto/monitor.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type ImageListInput struct {
9 | ClusterName string `json:"cluster_name" form:"cluster_name" validate:"required"`
10 | }
11 |
12 | type ImageListOut struct {
13 | Total int `json:"total"`
14 | List []ImageListItem `json:"list"`
15 | }
16 |
17 | type ImageListItem struct {
18 | ClusterName string `json:"cluster_name"`
19 | NameSpace string `json:"name_space"`
20 | AppName string `json:"app_name"`
21 | Image string `json:"image"`
22 | }
23 |
24 | func (params *ImageListInput) BindingValidParams(c *gin.Context) error {
25 | return pkg.DefaultGetValidParams(c, params)
26 | }
27 |
--------------------------------------------------------------------------------
/dto/kubeDto/namespace.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type NameSpaceNameInput struct {
9 | Name string `json:"name" form:"name" comment:"命名空间名称" validate:"required"`
10 | }
11 |
12 | type NameSpaceListInput struct {
13 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
14 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
15 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
16 | }
17 |
18 | func (params *NameSpaceListInput) BindingValidParams(c *gin.Context) error {
19 | return pkg.DefaultGetValidParams(c, params)
20 | }
21 |
22 | func (params *NameSpaceNameInput) BindingValidParams(c *gin.Context) error {
23 | return pkg.DefaultGetValidParams(c, params)
24 | }
25 |
--------------------------------------------------------------------------------
/dto/kubeDto/node.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type NodeNameInput struct {
9 | Name string `json:"name" form:"name" comment:"Node名称" validate:"required"`
10 | }
11 |
12 | type NodeListInput struct {
13 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
14 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
15 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
16 | }
17 |
18 | func (params *NodeNameInput) BindingValidParams(c *gin.Context) error {
19 | return pkg.DefaultGetValidParams(c, params)
20 | }
21 |
22 | func (params *NodeListInput) BindingValidParams(c *gin.Context) error {
23 | return pkg.DefaultGetValidParams(c, params)
24 | }
25 |
--------------------------------------------------------------------------------
/dto/kubeDto/persistentVolumeClaim.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type PersistentVolumeClaimNameNS struct {
9 | Name string `json:"name" form:"name" comment:"配置卷名称" validate:"required"`
10 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
11 | }
12 |
13 | type PersistentVolumeClaimUpdateInput struct {
14 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
15 | Content string `json:"content" form:"content" validate:"required" comment:"更新内容"`
16 | }
17 |
18 | type PersistentVolumeClaimListInput struct {
19 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
20 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
21 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
22 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
23 | }
24 |
25 | func (params *PersistentVolumeClaimNameNS) BindingValidParams(c *gin.Context) error {
26 | return pkg.DefaultGetValidParams(c, params)
27 | }
28 |
29 | func (params *PersistentVolumeClaimUpdateInput) BindingValidParams(c *gin.Context) error {
30 | return pkg.DefaultGetValidParams(c, params)
31 | }
32 |
33 | func (params *PersistentVolumeClaimListInput) BindingValidParams(c *gin.Context) error {
34 | return pkg.DefaultGetValidParams(c, params)
35 | }
36 |
--------------------------------------------------------------------------------
/dto/kubeDto/persistentvolume.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type PersistentVolumeNameInput struct {
9 | Name string `json:"name" form:"name" comment:"命名空间名称" validate:"required"`
10 | }
11 |
12 | type PersistentVolumeListInput struct {
13 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
14 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
15 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
16 | }
17 |
18 | func (params *PersistentVolumeListInput) BindingValidParams(c *gin.Context) error {
19 | return pkg.DefaultGetValidParams(c, params)
20 | }
21 |
22 | func (params *PersistentVolumeNameInput) BindingValidParams(c *gin.Context) error {
23 | return pkg.DefaultGetValidParams(c, params)
24 | }
25 |
--------------------------------------------------------------------------------
/dto/kubeDto/pod.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/pkg"
7 | )
8 |
9 | type PodListInput struct {
10 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
11 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
12 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
13 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
14 | }
15 |
16 | // WebShellOptions ws API 参数定义
17 | type WebShellOptions struct {
18 | Namespace string `form:"namespace"`
19 | Pod string `form:"pod_name"`
20 | Container string `form:"container_name"`
21 | }
22 |
23 | func (params *WebShellOptions) BindingValidParams(c *gin.Context) error {
24 | return pkg.DefaultGetValidParams(c, params)
25 | }
26 |
27 | func (params *PodListInput) BindingValidParams(c *gin.Context) error {
28 | return pkg.DefaultGetValidParams(c, params)
29 | }
30 |
31 | type PodNameNsInput struct {
32 | PodName string `json:"pod_name" form:"pod_name" comment:"POD名称" validate:"required"`
33 | NameSpace string `json:"name_space" form:"namespace" comment:"命名空间" validate:"required"`
34 | }
35 |
36 | type PodUpdateInput struct {
37 | PodName string `json:"pod_name" form:"pod_name" comment:"POD名称" validate:"required"`
38 | NameSpace string `json:"name_space" form:"namespace" comment:"命名空间" validate:"required"`
39 | Content string `json:"content" form:"content" comment:"内容" validate:"required"`
40 | }
41 |
42 | type PodGetLogInput struct {
43 | PodName string `json:"pod_name" form:"pod_name" comment:"POD名称" validate:"required"`
44 | NameSpace string `json:"name_space" form:"namespace" comment:"命名空间" validate:"required"`
45 | ContainerName string `json:"container_name" form:"container_name" comment:"容器名称" validate:"required"`
46 | }
47 |
48 | func (params *PodNameNsInput) BindingValidParams(c *gin.Context) error {
49 | return pkg.DefaultGetValidParams(c, params)
50 | }
51 |
52 | func (params *PodGetLogInput) BindingValidParams(c *gin.Context) error {
53 | return pkg.DefaultGetValidParams(c, params)
54 | }
55 |
56 | func (params *PodUpdateInput) BindingValidParams(c *gin.Context) error {
57 | return pkg.DefaultGetValidParams(c, params)
58 | }
59 |
--------------------------------------------------------------------------------
/dto/kubeDto/secret.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type SecretNameNS struct {
9 | Name string `json:"name" form:"name" comment:"有状态控制器名称" validate:"required"`
10 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
11 | }
12 |
13 | type SecretUpdateInput struct {
14 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
15 | Content string `json:"content" form:"content" validate:"required" comment:"更新内容"`
16 | }
17 |
18 | type SecretListInput struct {
19 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
20 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
21 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
22 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
23 | }
24 |
25 | func (params *SecretNameNS) BindingValidParams(c *gin.Context) error {
26 | return pkg.DefaultGetValidParams(c, params)
27 | }
28 |
29 | func (params *SecretUpdateInput) BindingValidParams(c *gin.Context) error {
30 | return pkg.DefaultGetValidParams(c, params)
31 | }
32 |
33 | func (params *SecretListInput) BindingValidParams(c *gin.Context) error {
34 | return pkg.DefaultGetValidParams(c, params)
35 | }
36 |
--------------------------------------------------------------------------------
/dto/kubeDto/service.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type ServiceCreateInput struct {
9 | Name string `json:"name"`
10 | NameSpace string `json:"namespace"`
11 | Type string `json:"type"`
12 | ContainerPort int32 `json:"container_port"`
13 | Port int32 `json:"port"`
14 | NodePort int32 `json:"node_port"`
15 | Label map[string]string `json:"label"`
16 | }
17 |
18 | type ServiceNameNS struct {
19 | Name string `json:"name" form:"name" comment:"服务名称" validate:"required"`
20 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
21 | }
22 |
23 | type ServiceUpdateInput struct {
24 | Content string `json:"content" validate:"required" comment:"更新内容"`
25 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
26 | }
27 |
28 | type ServiceListInput struct {
29 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
30 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
31 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
32 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
33 | }
34 |
35 | func (params *ServiceNameNS) BindingValidParams(c *gin.Context) error {
36 | return pkg.DefaultGetValidParams(c, params)
37 | }
38 |
39 | func (params *ServiceCreateInput) BindingValidParams(c *gin.Context) error {
40 | return pkg.DefaultGetValidParams(c, params)
41 | }
42 |
43 | func (params *ServiceUpdateInput) BindingValidParams(c *gin.Context) error {
44 | return pkg.DefaultGetValidParams(c, params)
45 | }
46 |
47 | func (params *ServiceListInput) BindingValidParams(c *gin.Context) error {
48 | return pkg.DefaultGetValidParams(c, params)
49 | }
50 |
--------------------------------------------------------------------------------
/dto/kubeDto/statefulset.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type StatefulSetNameNS struct {
9 | Name string `json:"name" form:"name" comment:"有状态控制器名称" validate:"required"`
10 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
11 | }
12 |
13 | type StatefulSetUpdateInput struct {
14 | NameSpace string `json:"namespace" form:"namespace" comment:"命名空间" validate:"required"`
15 | Content string `json:"content" form:"content" validate:"required" comment:"更新内容"`
16 | }
17 |
18 | type StatefulSetListInput struct {
19 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
20 | NameSpace string `json:"namespace" form:"namespace" validate:"" comment:"命名空间"`
21 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
22 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
23 | }
24 |
25 | func (params *StatefulSetNameNS) BindingValidParams(c *gin.Context) error {
26 | return pkg.DefaultGetValidParams(c, params)
27 | }
28 |
29 | func (params *StatefulSetUpdateInput) BindingValidParams(c *gin.Context) error {
30 | return pkg.DefaultGetValidParams(c, params)
31 | }
32 |
33 | func (params *StatefulSetListInput) BindingValidParams(c *gin.Context) error {
34 | return pkg.DefaultGetValidParams(c, params)
35 | }
36 |
--------------------------------------------------------------------------------
/dto/kubeDto/workflow.go:
--------------------------------------------------------------------------------
1 | package kubeDto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | )
7 |
8 | type WorkFlowListInput struct {
9 | FilterName string `json:"filter_name" form:"filter_name" validate:"" comment:"过滤名"`
10 | Limit int `json:"limit" form:"limit" validate:"" comment:"分页限制"`
11 | Page int `json:"page" form:"page" validate:"" comment:"页码"`
12 | }
13 |
14 | type WorkFlowCreateInput struct {
15 | Name string `json:"name"`
16 | NameSpace string `json:"namespace"`
17 | Replicas int32 `json:"replicas"`
18 | Deployment string `json:"deployment"`
19 | Image string `json:"image"`
20 | Label map[string]string `json:"label"`
21 | Cpu string `json:"cpu"`
22 | Memory string `json:"memory"`
23 | ContainerPort int32 `json:"container_port"`
24 | HealthPath string `json:"health_path"`
25 | HealthCheck bool `json:"healthCheck"`
26 | Type string `json:"type"`
27 | Port int32 `json:"port"`
28 | NodePort int32 `json:"node_port"`
29 | Hosts map[string][]*HttpPath `json:"hosts"`
30 | }
31 |
32 | type WorkFlowIDInput struct {
33 | ID int `json:"id" form:"id"`
34 | }
35 |
36 | func (params *WorkFlowCreateInput) BindingValidParams(c *gin.Context) error {
37 | return pkg.DefaultGetValidParams(c, params)
38 | }
39 |
40 | func (params *WorkFlowListInput) BindingValidParams(c *gin.Context) error {
41 | return pkg.DefaultGetValidParams(c, params)
42 | }
43 |
44 | func (params *WorkFlowIDInput) BindingValidParams(c *gin.Context) error {
45 | return pkg.DefaultGetValidParams(c, params)
46 | }
47 |
--------------------------------------------------------------------------------
/dto/menu.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/dao/model"
7 | "github.com/noovertime7/kubemanage/pkg"
8 | )
9 |
10 | type AddSysMenusInput struct {
11 | ParentId string `json:"parentId" comment:"父菜单ID" validate:"required"` // 父菜单ID
12 | Name string `json:"name" comment:"路由name" validate:"required"` // 路由name
13 | Path string `json:"path" comment:"路由path" validate:"required"` // 路由path
14 | Disabled bool `json:"disabled" comment:"是否禁用" validate:"required"` // 是否在列表隐藏
15 | Hidden bool `json:"hidden" comment:"是否在列表隐藏" validate:"required"` // 是否在列表隐藏
16 | Sort int `json:"sort" comment:"排序标记" validate:"required"` // 排序标记
17 | model.Meta
18 | }
19 |
20 | type SysMenusResponse struct {
21 | Menus []model.SysMenu `json:"menus"`
22 | }
23 |
24 | type SysBaseMenusResponse struct {
25 | Menus []model.SysBaseMenu `json:"menus"`
26 | }
27 |
28 | type SysBaseMenuResponse struct {
29 | Menu model.SysBaseMenu `json:"menu"`
30 | }
31 |
32 | type AddMenuAuthorityInput struct {
33 | Menus []model.SysBaseMenu `json:"menus"`
34 | AuthorityId uint `json:"authorityId" validate:"required"` // 角色ID
35 | }
36 |
37 | // BindingValidParams 绑定并校验参数
38 | func (a *AddSysMenusInput) BindingValidParams(ctx *gin.Context) error {
39 | return pkg.DefaultGetValidParams(ctx, a)
40 | }
41 |
42 | // BindingValidParams 绑定并校验参数
43 | func (a *AddMenuAuthorityInput) BindingValidParams(ctx *gin.Context) error {
44 | return pkg.DefaultGetValidParams(ctx, a)
45 | }
46 |
--------------------------------------------------------------------------------
/dto/operation.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/dao/model"
7 | "github.com/noovertime7/kubemanage/pkg"
8 | )
9 |
10 | type OperationListInput struct {
11 | PageInfo
12 | Method string `json:"method" form:"method" ` // 请求方法
13 | Path string `json:"path" form:"path" ` // 请求路径
14 | Status int `json:"status" form:"status" ` // 请求状态
15 | }
16 |
17 | type OperationListOutPut struct {
18 | Total int64 `json:"total"`
19 | OperationList []*model.SysOperationRecord `json:"list"`
20 | PageInfo
21 | }
22 |
23 | // BindingValidParams 绑定并校验参数
24 | func (o *OperationListInput) BindingValidParams(ctx *gin.Context) error {
25 | return pkg.DefaultGetValidParams(ctx, o)
26 | }
27 |
--------------------------------------------------------------------------------
/dto/user.go:
--------------------------------------------------------------------------------
1 | package dto
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "github.com/noovertime7/kubemanage/pkg"
7 | )
8 |
9 | type AdminLoginInput struct {
10 | UserName string `form:"username" json:"username" comment:"用户名" validate:"required" example:"用户名"`
11 | Password string `form:"password" json:"password" comment:"密码" validate:"required" example:"密码"`
12 | }
13 |
14 | type AdminLoginOut struct {
15 | Token string `form:"token" json:"token" comment:"token" example:"token"`
16 | }
17 |
18 | type UserInfoOut struct {
19 | User model.SysUser `json:"user"`
20 | Menus []model.SysMenu `json:"menus"`
21 | RuleNames []string `json:"ruleNames"`
22 | }
23 |
24 | type SetUserAuth struct {
25 | AuthorityId uint `json:"authorityId"` // 角色ID
26 | }
27 |
28 | type ChangeUserPwdInput struct {
29 | OldPwd string `json:"old_pwd" form:"old_pwd" comment:"原密码" validate:"required"`
30 | NewPwd string `json:"new_pwd" form:"new_pwd" comment:"new_pwd" validate:"required"`
31 | }
32 |
33 | // BindingValidParams 绑定并校验参数
34 | func (a *ChangeUserPwdInput) BindingValidParams(ctx *gin.Context) error {
35 | return pkg.DefaultGetValidParams(ctx, a)
36 | }
37 |
38 | // BindingValidParams 绑定并校验参数
39 | func (a *SetUserAuth) BindingValidParams(ctx *gin.Context) error {
40 | return pkg.DefaultGetValidParams(ctx, a)
41 | }
42 |
43 | // BindingValidParams 绑定并校验参数
44 | func (a *AdminLoginInput) BindingValidParams(ctx *gin.Context) error {
45 | return pkg.DefaultGetValidParams(ctx, a)
46 | }
47 |
--------------------------------------------------------------------------------
/img/cm_detail.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/cm_detail.jpg
--------------------------------------------------------------------------------
/img/cmdb/host.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/cmdb/host.png
--------------------------------------------------------------------------------
/img/cmdb/webshell.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/cmdb/webshell.png
--------------------------------------------------------------------------------
/img/dashboard.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/dashboard.jpg
--------------------------------------------------------------------------------
/img/deployment.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/deployment.jpg
--------------------------------------------------------------------------------
/img/namespace.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/namespace.jpg
--------------------------------------------------------------------------------
/img/node.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/node.jpg
--------------------------------------------------------------------------------
/img/operation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/operation.png
--------------------------------------------------------------------------------
/img/pod.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/pod.jpg
--------------------------------------------------------------------------------
/img/pod_log.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/pod_log.jpg
--------------------------------------------------------------------------------
/img/pod_ter.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/pod_ter.jpg
--------------------------------------------------------------------------------
/img/rbac/api_rbac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/rbac/api_rbac.png
--------------------------------------------------------------------------------
/img/rbac/menu_rbac.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/rbac/menu_rbac.png
--------------------------------------------------------------------------------
/img/service.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/service.jpg
--------------------------------------------------------------------------------
/img/system_state.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/system_state.png
--------------------------------------------------------------------------------
/img/user.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/user.png
--------------------------------------------------------------------------------
/img/wordflow.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/noovertime7/kubemanage/10cedd820104fb18400d386907ecd54ec0bec553/img/wordflow.jpg
--------------------------------------------------------------------------------
/middleware/casbin_rbac.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "fmt"
5 | "strconv"
6 |
7 | "github.com/gin-gonic/gin"
8 |
9 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
10 | "github.com/noovertime7/kubemanage/pkg/globalError"
11 | "github.com/noovertime7/kubemanage/pkg/utils"
12 | )
13 |
14 | // CasbinHandler 拦截器
15 | func CasbinHandler() gin.HandlerFunc {
16 | return func(c *gin.Context) {
17 | if AlwaysAllowPath.Has(c.Request.URL.Path) {
18 | return
19 | }
20 | waitUse, err := utils.GetClaims(c)
21 | if err != nil {
22 | ResponseError(c, globalError.NewGlobalError(globalError.ServerError, err))
23 | c.Abort()
24 | return
25 | }
26 | // 获取请求的PATH
27 | obj := c.Request.URL.Path
28 | // 获取请求方法
29 | act := c.Request.Method
30 | // 获取用户的角色
31 | sub := strconv.Itoa(int(waitUse.AuthorityId))
32 | e := v1.CoreV1.System().CasbinService().Casbin() // 判断策略中是否存在
33 | success, _ := e.Enforce(sub, obj, act)
34 | if success {
35 | c.Next()
36 | } else {
37 | ResponseError(c, globalError.NewGlobalError(globalError.AuthErr, fmt.Errorf("角色ID %d 请求 %s %s 无权限", waitUse.AuthorityId, act, obj)))
38 | c.Abort()
39 | return
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/middleware/cors.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "time"
5 |
6 | "github.com/gin-contrib/cors"
7 | "github.com/gin-gonic/gin"
8 | )
9 |
10 | // Cores 处理跨域请求,支持options访问
11 | func Cores() gin.HandlerFunc {
12 | c := cors.Config{
13 | AllowAllOrigins: true,
14 | AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "PATCH"},
15 | AllowHeaders: []string{"Content-Type", "Access-Token", "Authorization"},
16 | MaxAge: 6 * time.Hour,
17 | }
18 |
19 | return cors.New(c)
20 | }
21 |
--------------------------------------------------------------------------------
/middleware/jwt.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg/globalError"
6 | "github.com/noovertime7/kubemanage/pkg/utils"
7 | )
8 |
9 | // JWTAuth jwt认证函数
10 | func JWTAuth() gin.HandlerFunc {
11 | return func(context *gin.Context) {
12 | if AlwaysAllowPath.Has(context.Request.URL.Path) {
13 | return
14 | }
15 |
16 | if len(context.Request.URL.String()) == 15 && context.Request.URL.String()[0:15] == "/api/user/login" {
17 | context.Next()
18 | return
19 | }
20 | // 处理验证逻辑
21 | claims, err := utils.GetClaims(context)
22 | if err != nil {
23 | ResponseError(context, globalError.NewGlobalError(globalError.AuthorizationError, err))
24 | context.Abort()
25 | return
26 | }
27 | // 继续交由下一个路由处理,并将解析出的信息传递下去
28 | context.Set("claims", claims)
29 | context.Next()
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/middleware/limiter.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The Pixiu Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package middleware
18 |
19 | import (
20 | "fmt"
21 | "github.com/gin-gonic/gin"
22 | "github.com/noovertime7/kubemanage/pkg/globalError"
23 | "golang.org/x/time/rate"
24 | )
25 |
26 | func Limiter() gin.HandlerFunc {
27 |
28 | // 初始化一个限速器,每秒产生 1000 个令牌,桶的大小为 1000 个
29 | // 初始化状态桶是满的
30 |
31 | limiter := rate.NewLimiter(1000, 1000)
32 |
33 | return func(c *gin.Context) {
34 | if !limiter.Allow() {
35 | ResponseError(c, globalError.NewGlobalError(globalError.ServerError, fmt.Errorf("系统繁忙,请稍后重试")))
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/middleware/log.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg/logger"
6 | "go.uber.org/zap"
7 | "time"
8 | )
9 |
10 | // Logger 接收gin框架默认的日志
11 | func Logger() gin.HandlerFunc {
12 | return func(c *gin.Context) {
13 | start := time.Now()
14 | path := c.Request.URL.Path
15 | query := c.Request.URL.RawQuery
16 | c.Next()
17 |
18 | cost := time.Since(start)
19 | logger.LG.Info(path,
20 | zap.Int("status", c.Writer.Status()),
21 | zap.String("method", c.Request.Method),
22 | zap.String("path", path),
23 | zap.String("query", query),
24 | zap.String("ip", c.ClientIP()),
25 | zap.String("user-agent", c.Request.UserAgent()),
26 | zap.String("errors", c.Errors.ByType(gin.ErrorTypePrivate).String()),
27 | zap.String("host", c.Request.Host),
28 | zap.Duration("cost", cost),
29 | )
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/middleware/middleware.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | "k8s.io/apimachinery/pkg/util/sets"
7 | )
8 |
9 | var AlwaysAllowPath sets.String
10 |
11 | func InstallMiddlewares(ginEngine *gin.RouterGroup) {
12 | // 初始化可忽略的请求路径
13 | AlwaysAllowPath = sets.NewString(pkg.LoginURL, pkg.LogoutURL, pkg.WebShellURL)
14 | ginEngine.Use(Logger(), Cores(), Limiter(), Recovery(true), TranslationMiddleware(), JWTAuth(), CasbinHandler())
15 | }
16 |
--------------------------------------------------------------------------------
/middleware/operation.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "bytes"
5 | "encoding/json"
6 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1"
7 | "io"
8 | "net/http"
9 | "net/url"
10 | "strings"
11 | "sync"
12 | "time"
13 |
14 | "github.com/gin-gonic/gin"
15 | "go.uber.org/zap"
16 |
17 | "github.com/noovertime7/kubemanage/dao/model"
18 | "github.com/noovertime7/kubemanage/pkg/logger"
19 | "github.com/noovertime7/kubemanage/pkg/utils"
20 | )
21 |
22 | var respPool sync.Pool
23 |
24 | func init() {
25 | respPool.New = func() interface{} {
26 | return make([]byte, 1024)
27 | }
28 | }
29 |
30 | func OperationRecord() gin.HandlerFunc {
31 | return func(c *gin.Context) {
32 | if AlwaysAllowPath.Has(c.Request.URL.Path) {
33 | return
34 | }
35 | var (
36 | err error
37 | userId int
38 | body []byte
39 | )
40 | //如果请求不是get请求,从body中获取数据
41 | if c.Request.Method != http.MethodGet {
42 | var err error
43 | body, err = io.ReadAll(c.Request.Body)
44 | if err != nil {
45 | logger.LG.Error("read body from request error:", zap.Error(err))
46 | } else {
47 | c.Request.Body = io.NopCloser(bytes.NewBuffer(body))
48 | }
49 | } else {
50 | query := c.Request.URL.RawQuery
51 | query, _ = url.QueryUnescape(query)
52 | split := strings.Split(query, "&")
53 | m := make(map[string]string)
54 | for _, v := range split {
55 | kv := strings.Split(v, "=")
56 | if len(kv) == 2 {
57 | m[kv[0]] = kv[1]
58 | }
59 | }
60 | if len(m) > 0 {
61 | body, err = json.Marshal(&m)
62 | if err != nil {
63 | logger.LG.Error("marshal body error:", zap.Error(err))
64 | body = []byte{}
65 | }
66 | }
67 | }
68 | claims, err := utils.GetClaims(c)
69 | if err != nil {
70 | logger.LG.Error("get claims from token err:", zap.Error(err))
71 | return
72 | }
73 | userId = claims.ID
74 | record := model.SysOperationRecord{
75 | Ip: c.ClientIP(),
76 | Method: c.Request.Method,
77 | Path: c.Request.URL.Path,
78 | Agent: c.Request.UserAgent(),
79 | Body: string(body),
80 | UserID: userId,
81 | }
82 | //if len(record.Body) > 1024 {
83 | // // 截断
84 | // newBody := respPool.Get().([]byte)
85 | // copy(newBody, record.Body)
86 | // record.Body = string(newBody)
87 | // defer respPool.Put(newBody[:0])
88 | //}
89 | writer := responseBodyWriter{
90 | ResponseWriter: c.Writer,
91 | body: &bytes.Buffer{},
92 | }
93 | c.Writer = writer
94 | now := time.Now()
95 |
96 | c.Next()
97 |
98 | latency := time.Since(now)
99 | record.ErrorMessage = c.Errors.ByType(gin.ErrorTypePrivate).String()
100 | record.Status = c.Writer.Status()
101 | record.Latency = latency
102 | record.Resp = writer.body.String()
103 | //
104 | //if len(record.Resp) > 1024 {
105 | // // 截断
106 | // newBody := respPool.Get().([]byte)
107 | // copy(newBody, record.Resp)
108 | // record.Resp = string(newBody)
109 | // defer respPool.Put(newBody[:0])
110 | //}
111 |
112 | if err := v1.CoreV1.System().Operation().CreateOperationRecord(c, &record); err != nil {
113 | logger.LG.Error("create operation record error:", zap.Error(err))
114 | }
115 | }
116 | }
117 |
118 | type responseBodyWriter struct {
119 | gin.ResponseWriter
120 | body *bytes.Buffer
121 | }
122 |
123 | func (r responseBodyWriter) Write(b []byte) (int, error) {
124 | r.body.Write(b)
125 | return r.ResponseWriter.Write(b)
126 | }
127 |
--------------------------------------------------------------------------------
/middleware/recovery.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg/logger"
6 | "net"
7 | "net/http"
8 | "net/http/httputil"
9 | "os"
10 | "runtime/debug"
11 | "strings"
12 |
13 | "go.uber.org/zap"
14 | )
15 |
16 | // Recovery 使用自定义日志库替换原有recover中间件
17 | func Recovery(stack bool) gin.HandlerFunc {
18 | return func(c *gin.Context) {
19 | defer func() {
20 | if err := recover(); err != nil {
21 | // Check for a broken connection, as it is not really a
22 | // condition that warrants a panic stack trace.
23 | var brokenPipe bool
24 | if ne, ok := err.(*net.OpError); ok {
25 | if se, ok := ne.Err.(*os.SyscallError); ok {
26 | if strings.Contains(strings.ToLower(se.Error()), "broken pipe") || strings.Contains(strings.ToLower(se.Error()), "connection reset by peer") {
27 | brokenPipe = true
28 | }
29 | }
30 | }
31 |
32 | httpRequest, _ := httputil.DumpRequest(c.Request, false)
33 | if brokenPipe {
34 | logger.LG.Error(c.Request.URL.Path,
35 | zap.Any("error", err),
36 | zap.String("request", string(httpRequest)),
37 | )
38 | // If the connection is dead, we can't write a status to it.
39 | c.Error(err.(error)) // nolint: errcheck
40 | c.Abort()
41 | return
42 | }
43 |
44 | if stack {
45 | logger.LG.Error("[Recovery from panic]",
46 | zap.Any("error", err),
47 | zap.String("request", string(httpRequest)),
48 | zap.String("stack", string(debug.Stack())),
49 | )
50 | } else {
51 | logger.LG.Error("[Recovery from panic]",
52 | zap.Any("error", err),
53 | zap.String("request", string(httpRequest)),
54 | )
55 | }
56 | c.AbortWithStatus(http.StatusInternalServerError)
57 | }
58 | }()
59 | c.Next()
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/middleware/response.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "encoding/json"
5 | "github.com/gin-gonic/gin"
6 | "github.com/noovertime7/kubemanage/pkg/globalError"
7 | "github.com/pkg/errors"
8 | "net/http"
9 | )
10 |
11 | type ResponseCode int
12 |
13 | type Response struct {
14 | Code ResponseCode `json:"code"`
15 | Msg string `json:"msg"`
16 | RealErr string `json:"real_err"`
17 | Data interface{} `json:"data"`
18 | }
19 |
20 | func ResponseSuccess(c *gin.Context, data interface{}) {
21 | resp := &Response{Code: http.StatusOK, Msg: "", Data: data}
22 | tempMsg, ok := data.(string)
23 | if ok && tempMsg == "" {
24 | resp.Msg = "操作成功"
25 | }
26 | c.JSON(200, resp)
27 | response, _ := json.Marshal(resp)
28 | c.Set("response", string(response))
29 | }
30 |
31 | func ResponseError(c *gin.Context, err error) {
32 | //判断错误类型
33 | // As - 获取错误的具体实现
34 | var code ResponseCode
35 | var myError = new(globalError.GlobalError)
36 | if errors.As(err, &myError) {
37 | code = ResponseCode(myError.Code)
38 | }
39 | resp := &Response{Code: code, Msg: err.Error(), RealErr: myError.RealErrorMessage, Data: ""}
40 | c.JSON(200, resp)
41 | response, _ := json.Marshal(resp)
42 | c.Set("response", string(response))
43 | }
44 |
--------------------------------------------------------------------------------
/middleware/translation.go:
--------------------------------------------------------------------------------
1 | package middleware
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-playground/locales/en"
6 | "github.com/go-playground/locales/zh"
7 | "github.com/go-playground/universal-translator"
8 | "github.com/noovertime7/kubemanage/pkg"
9 | "gopkg.in/go-playground/validator.v9"
10 | en_translations "gopkg.in/go-playground/validator.v9/translations/en"
11 | zh_translations "gopkg.in/go-playground/validator.v9/translations/zh"
12 | "reflect"
13 | )
14 |
15 | // 设置Translation
16 | func TranslationMiddleware() gin.HandlerFunc {
17 | return func(c *gin.Context) {
18 | //参照:https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go
19 |
20 | //设置支持语言
21 | enLan := en.New()
22 | zhLan := zh.New()
23 |
24 | //设置国际化翻译器
25 | uni := ut.New(zhLan, zhLan, enLan)
26 | val := validator.New()
27 |
28 | //根据参数取翻译器实例
29 | locale := c.DefaultQuery("locale", "zh")
30 | trans, _ := uni.GetTranslator(locale)
31 |
32 | //翻译器注册到validator
33 | switch locale {
34 | case "en":
35 | err := en_translations.RegisterDefaultTranslations(val, trans)
36 | if err != nil {
37 | return
38 | }
39 | val.RegisterTagNameFunc(func(fld reflect.StructField) string {
40 | return fld.Tag.Get("en_comment")
41 | })
42 | break
43 | default:
44 | err := zh_translations.RegisterDefaultTranslations(val, trans)
45 | if err != nil {
46 | return
47 | }
48 | val.RegisterTagNameFunc(func(fld reflect.StructField) string {
49 | return fld.Tag.Get("comment")
50 | })
51 |
52 | ////自定义验证方法
53 | ////https://github.com/go-playground/validator/blob/v9/_examples/custom-validation/main.go
54 | //val.RegisterValidation("is-validuser", func(fl validator.FieldLevel) bool {
55 | // return fl.Field().String() == "admin"
56 | //})
57 | //
58 | ////自定义验证器
59 | ////https://github.com/go-playground/validator/blob/v9/_examples/translations/main.go
60 | //val.RegisterTranslation("is-validuser", trans, func(ut ut.Translator) error {
61 | // return ut.Add("is-validuser", "{0} 填写不正确哦", true)
62 | //}, func(ut ut.Translator, fe validator.FieldError) string {
63 | // t, _ := ut.T("is-validuser", fe.Field())
64 | // return t
65 | //})
66 | break
67 | }
68 | c.Set(pkg.TranslatorKey, trans)
69 | c.Set(pkg.ValidatorKey, val)
70 | c.Next()
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/pkg/const.go:
--------------------------------------------------------------------------------
1 | package pkg
2 |
3 | import "strconv"
4 |
5 | const (
6 | ValidatorKey = "ValidatorKey"
7 | TranslatorKey = "TranslatorKey"
8 | )
9 |
10 | const (
11 | LoginURL = "/api/user/login"
12 | LogoutURL = "/api/user/logout"
13 | WebShellURL = "/api/k8s/pod/webshell"
14 | )
15 |
16 | var (
17 | AdminDefaultAuth uint = 111
18 | AdminDefaultAuthStr = strconv.Itoa(int(AdminDefaultAuth))
19 | UserDefaultAuth uint = 222
20 | UserDefaultAuthStr = strconv.Itoa(int(UserDefaultAuth))
21 | UserSubDefaultAuth uint = 2221
22 | UserSubDefaultAuthStr = strconv.Itoa(int(UserSubDefaultAuth))
23 | )
24 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/cloud.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/noovertime7/kubemanage/dao"
5 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1/kube"
6 | )
7 |
8 | type CloudGetter interface {
9 | Cloud() CloudInterface
10 | }
11 |
12 | type CloudInterface interface {
13 | kube.PodsGetter
14 | }
15 |
16 | type cloud struct {
17 | app *KubeManage
18 | factory dao.ShareDaoFactory
19 | }
20 |
21 | func (c *cloud) Pods(cloud string) kube.PodInterface {
22 | // TODO 临时添加,需要重构
23 | return kube.NewPods(nil, "", c.factory)
24 | }
25 |
26 | func NewCloud(c *KubeManage) CloudInterface {
27 | return &cloud{
28 | app: c,
29 | factory: c.Factory,
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/interface.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/noovertime7/kubemanage/cmd/app/config"
5 | "github.com/noovertime7/kubemanage/dao"
6 | "github.com/noovertime7/kubemanage/pkg/logger"
7 | )
8 |
9 | type CoreService interface {
10 | WorkFlowServiceGetter
11 | CloudGetter
12 | SystemGetter
13 | }
14 |
15 | func New(cfg *config.Config, factory dao.ShareDaoFactory) CoreService {
16 | return &KubeManage{
17 | Cfg: cfg,
18 | Factory: factory,
19 | }
20 | }
21 |
22 | type Logger interface {
23 | logger.Logger
24 | }
25 |
26 | type KubeManage struct {
27 | Cfg *config.Config
28 | Factory dao.ShareDaoFactory
29 | }
30 |
31 | func (c *KubeManage) WorkFlow() WorkFlowService {
32 | return NewWorkFlow(c)
33 | }
34 |
35 | func (c *KubeManage) Cloud() CloudInterface {
36 | return NewCloud(c)
37 | }
38 |
39 | func (c *KubeManage) System() SystemInterface {
40 | return NewSystem(c)
41 | }
42 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/configmap.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 |
7 | coreV1 "k8s.io/api/core/v1"
8 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | var Configmap configmap
12 |
13 | type configmap struct{}
14 |
15 | type ConfigmapResp struct {
16 | Total int `json:"total"`
17 | Items []coreV1.ConfigMap `json:"items"`
18 | }
19 |
20 | type ConfigmapNp struct {
21 | NameSpace string `json:"namespace"`
22 | ConfigmapNum int `json:"configmap_num"`
23 | }
24 |
25 | func (d *configmap) toCells(Configmaps []coreV1.ConfigMap) []DataCell {
26 | cells := make([]DataCell, len(Configmaps))
27 | for i := range Configmaps {
28 | cells[i] = configmapCell(Configmaps[i])
29 | }
30 | return cells
31 | }
32 |
33 | func (d *configmap) FromCells(cells []DataCell) []coreV1.ConfigMap {
34 | Configmaps := make([]coreV1.ConfigMap, len(cells))
35 | for i := range cells {
36 | Configmaps[i] = coreV1.ConfigMap(cells[i].(configmapCell))
37 | }
38 | return Configmaps
39 | }
40 |
41 | func (d *configmap) GetConfigmaps(filterName, namespace string, limit, page int) (*ConfigmapResp, error) {
42 | ConfigmapList, err := K8s.ClientSet.CoreV1().ConfigMaps(namespace).List(context.TODO(), metaV1.ListOptions{})
43 | if err != nil {
44 | return nil, err
45 | }
46 | selectableData := &dataSelector{
47 | GenericDataList: d.toCells(ConfigmapList.Items),
48 | DataSelect: &DataSelectQuery{
49 | Filter: &FilterQuery{Name: filterName},
50 | Paginatite: &PaginateQuery{
51 | Limit: limit,
52 | Page: page,
53 | },
54 | },
55 | }
56 | filterd := selectableData.Filter()
57 | total := len(filterd.GenericDataList)
58 | data := filterd.Sort().Paginate()
59 | Configmaps := d.FromCells(data.GenericDataList)
60 | return &ConfigmapResp{
61 | Total: total,
62 | Items: Configmaps,
63 | }, nil
64 | }
65 |
66 | func (d *configmap) GetConfigmapDetail(name, namespace string) (*coreV1.ConfigMap, error) {
67 | data, err := K8s.ClientSet.CoreV1().ConfigMaps(namespace).Get(context.TODO(), name, metaV1.GetOptions{})
68 | if err != nil {
69 | return nil, err
70 | }
71 | return data, nil
72 | }
73 |
74 | func (d *configmap) DeleteConfigmap(name, namespace string) error {
75 | return K8s.ClientSet.CoreV1().ConfigMaps(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
76 | }
77 |
78 | func (d *configmap) UpdateConfigmap(content, namespace string) error {
79 | var Configmap = &coreV1.ConfigMap{}
80 | if err := json.Unmarshal([]byte(content), Configmap); err != nil {
81 | return err
82 | }
83 | if _, err := K8s.ClientSet.CoreV1().ConfigMaps(namespace).Update(context.TODO(), Configmap, metaV1.UpdateOptions{}); err != nil {
84 | return err
85 | }
86 | return nil
87 | }
88 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/daemonset.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 |
7 | appsV1 "k8s.io/api/apps/v1"
8 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | var DaemonSet daemonSet
12 |
13 | type daemonSet struct {
14 | }
15 |
16 | type DaemonSetResp struct {
17 | Total int `json:"total"`
18 | Items []appsV1.DaemonSet `json:"items"`
19 | }
20 |
21 | type DaemonSetNp struct {
22 | NameSpace string `json:"namespace"`
23 | DaemonSetNum int `json:"daemonset_num"`
24 | }
25 |
26 | func (d *daemonSet) toCells(daemonsets []appsV1.DaemonSet) []DataCell {
27 | cells := make([]DataCell, len(daemonsets))
28 | for i := range daemonsets {
29 | cells[i] = daemonSetCell(daemonsets[i])
30 | }
31 | return cells
32 | }
33 |
34 | func (d *daemonSet) FromCells(cells []DataCell) []appsV1.DaemonSet {
35 | daemonSets := make([]appsV1.DaemonSet, len(cells))
36 | for i := range cells {
37 | daemonSets[i] = appsV1.DaemonSet(cells[i].(daemonSetCell))
38 | }
39 | return daemonSets
40 | }
41 |
42 | func (d *daemonSet) GetDaemonSets(filterName, namespace string, limit, page int) (*DaemonSetResp, error) {
43 | daemonSetList, err := K8s.ClientSet.AppsV1().DaemonSets(namespace).List(context.TODO(), metaV1.ListOptions{})
44 | if err != nil {
45 | return nil, err
46 | }
47 | selectableData := &dataSelector{
48 | GenericDataList: d.toCells(daemonSetList.Items),
49 | DataSelect: &DataSelectQuery{
50 | Filter: &FilterQuery{Name: filterName},
51 | Paginatite: &PaginateQuery{
52 | Limit: limit,
53 | Page: page,
54 | },
55 | },
56 | }
57 | filterd := selectableData.Filter()
58 | total := len(filterd.GenericDataList)
59 | data := filterd.Sort().Paginate()
60 | daemonSets := d.FromCells(data.GenericDataList)
61 | return &DaemonSetResp{
62 | Total: total,
63 | Items: daemonSets,
64 | }, nil
65 | }
66 |
67 | func (d *daemonSet) GetDaemonSetDetail(name, namespace string) (*appsV1.DaemonSet, error) {
68 | data, err := K8s.ClientSet.AppsV1().DaemonSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{})
69 | if err != nil {
70 | return nil, err
71 | }
72 | return data, nil
73 | }
74 |
75 | func (d *daemonSet) DeleteDaemonSet(name, namespace string) error {
76 | return K8s.ClientSet.AppsV1().DaemonSets(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
77 | }
78 |
79 | func (d *daemonSet) UpdateDaemonSet(content, namespace string) error {
80 | var daemonset = &appsV1.DaemonSet{}
81 | if err := json.Unmarshal([]byte(content), daemonset); err != nil {
82 | return err
83 | }
84 | if _, err := K8s.ClientSet.AppsV1().DaemonSets(namespace).Update(context.TODO(), daemonset, metaV1.UpdateOptions{}); err != nil {
85 | return err
86 | }
87 | return nil
88 | }
89 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/init.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "flag"
5 | "github.com/noovertime7/kubemanage/pkg/logger"
6 | "os"
7 | "path/filepath"
8 |
9 | "k8s.io/client-go/kubernetes"
10 | "k8s.io/client-go/rest"
11 | "k8s.io/client-go/tools/clientcmd"
12 | )
13 |
14 | var K8s k8s
15 |
16 | type k8s struct {
17 | Config *rest.Config
18 | ClientSet *kubernetes.Clientset
19 | }
20 |
21 | func (k *k8s) Init() error {
22 | var err error
23 | var config *rest.Config
24 | var kubeConfig *string
25 |
26 | if home := homeDir(); home != "" {
27 | kubeConfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
28 | } else {
29 | kubeConfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
30 | }
31 | flag.Parse()
32 |
33 | // 使用 ServiceAccount 创建集群配置(InCluster模式)
34 | if config, err = rest.InClusterConfig(); err != nil {
35 | // 使用 KubeConfig 文件创建集群配置
36 | if config, err = clientcmd.BuildConfigFromFlags("", *kubeConfig); err != nil {
37 | return err
38 | }
39 | }
40 |
41 | // 创建 clientSet
42 | clientSet, err := kubernetes.NewForConfig(config)
43 | if err != nil {
44 | return err
45 | }
46 | log := logger.New()
47 | log.Info("获取k8s clientSet 成功")
48 | k.ClientSet = clientSet
49 | k.Config = config
50 | return nil
51 | }
52 |
53 | func homeDir() string {
54 | if h := os.Getenv("HOME"); h != "" {
55 | return h
56 | }
57 | return os.Getenv("USERPROFILE") // windows
58 | }
59 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/namespace.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "github.com/pkg/errors"
6 | coreV1 "k8s.io/api/core/v1"
7 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | )
9 |
10 | var NameSpace namespace
11 |
12 | type namespace struct{}
13 |
14 | type NameSpaceResp struct {
15 | Total int `json:"total"`
16 | Items []coreV1.Namespace `json:"items"`
17 | }
18 |
19 | func (n *namespace) toCells(nodes []coreV1.Namespace) []DataCell {
20 | cells := make([]DataCell, len(nodes))
21 | for i := range nodes {
22 | cells[i] = namespaceCell(nodes[i])
23 | }
24 | return cells
25 | }
26 |
27 | func (n *namespace) FromCells(cells []DataCell) []coreV1.Namespace {
28 | nodes := make([]coreV1.Namespace, len(cells))
29 | for i := range cells {
30 | nodes[i] = coreV1.Namespace(cells[i].(namespaceCell))
31 | }
32 | return nodes
33 | }
34 |
35 | func (n *namespace) GetNameSpaces(filterName string, limit, page int) (nodesResp *NameSpaceResp, err error) {
36 | NamespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metaV1.ListOptions{})
37 | if err != nil {
38 | return nil, errors.New("获取Pod列表失败")
39 | }
40 | //实例化dataSelector结构体,组装数据
41 | selectableData := &dataSelector{
42 | GenericDataList: n.toCells(NamespaceList.Items),
43 | DataSelect: &DataSelectQuery{
44 | Filter: &FilterQuery{Name: filterName},
45 | Paginatite: &PaginateQuery{limit, page},
46 | },
47 | }
48 | //先过滤
49 | filtered := selectableData.Filter()
50 | total := len(filtered.GenericDataList)
51 | //排序、分页
52 | data := filtered.Sort().Paginate()
53 | //将dataCell类型转换为coreV1.Pod
54 | namespaces := n.FromCells(data.GenericDataList)
55 | return &NameSpaceResp{
56 | total,
57 | namespaces,
58 | }, nil
59 | }
60 |
61 | // GetNameSpacesDetail 获取Node详情
62 | func (n *namespace) GetNameSpacesDetail(Name string) (*coreV1.Namespace, error) {
63 | namespacesRes, err := K8s.ClientSet.CoreV1().Namespaces().Get(context.TODO(), Name, metaV1.GetOptions{})
64 | if err != nil {
65 | return nil, err
66 | }
67 | return namespacesRes, nil
68 | }
69 |
70 | func (n *namespace) CreateNameSpace(name string) error {
71 | ns := &coreV1.Namespace{
72 | TypeMeta: metaV1.TypeMeta{},
73 | ObjectMeta: metaV1.ObjectMeta{
74 | Name: name,
75 | },
76 | Spec: coreV1.NamespaceSpec{},
77 | Status: coreV1.NamespaceStatus{},
78 | }
79 | if _, err := K8s.ClientSet.CoreV1().Namespaces().Create(context.TODO(), ns, metaV1.CreateOptions{}); err != nil {
80 | return err
81 | }
82 | return nil
83 | }
84 |
85 | func (n *namespace) DeleteNameSpace(name string) error {
86 | return K8s.ClientSet.CoreV1().Namespaces().Delete(context.TODO(), name, metaV1.DeleteOptions{})
87 | }
88 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/node.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 |
6 | coreV1 "k8s.io/api/core/v1"
7 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | )
9 |
10 | var Node node
11 |
12 | type node struct{}
13 |
14 | type NodeResp struct {
15 | Total int `json:"total"`
16 | Items []coreV1.Node `json:"items"`
17 | }
18 |
19 | func (n *node) toCells(nodes []coreV1.Node) []DataCell {
20 | cells := make([]DataCell, len(nodes))
21 | for i := range nodes {
22 | cells[i] = nodeCell(nodes[i])
23 | }
24 | return cells
25 | }
26 |
27 | func (n *node) FromCells(cells []DataCell) []coreV1.Node {
28 | nodes := make([]coreV1.Node, len(cells))
29 | for i := range cells {
30 | nodes[i] = coreV1.Node(cells[i].(nodeCell))
31 | }
32 | return nodes
33 | }
34 |
35 | func (n *node) GetNodes(filterName string, limit, page int) (nodesResp *NodeResp, err error) {
36 | nodeList, err := K8s.ClientSet.CoreV1().Nodes().List(context.TODO(), metaV1.ListOptions{})
37 | if err != nil {
38 | return nil, err
39 | }
40 | //实例化dataSelector结构体,组装数据
41 | selectableData := &dataSelector{
42 | GenericDataList: n.toCells(nodeList.Items),
43 | DataSelect: &DataSelectQuery{
44 | Filter: &FilterQuery{Name: filterName},
45 | Paginatite: &PaginateQuery{limit, page},
46 | },
47 | }
48 | //先过滤
49 | filtered := selectableData.Filter()
50 | total := len(filtered.GenericDataList)
51 | //排序、分页
52 | data := filtered.Sort().Paginate()
53 | //将dataCell类型转换为coreV1.Pod
54 | nodes := n.FromCells(data.GenericDataList)
55 | return &NodeResp{
56 | total,
57 | nodes,
58 | }, nil
59 | }
60 |
61 | // GetNodeDetail 获取Node详情
62 | func (n *node) GetNodeDetail(Name string) (*coreV1.Node, error) {
63 | nodeRes, err := K8s.ClientSet.CoreV1().Nodes().Get(context.TODO(), Name, metaV1.GetOptions{})
64 | if err != nil {
65 | return nil, err
66 | }
67 | return nodeRes, nil
68 | }
69 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/persistentVolumeClaim.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | coreV1 "k8s.io/api/core/v1"
7 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | )
9 |
10 | var PersistentVolumeClaim persistentVolumeClaim
11 |
12 | type persistentVolumeClaim struct {
13 | }
14 |
15 | type PersistentVolumeClaimResp struct {
16 | Total int `json:"total"`
17 | Items []coreV1.PersistentVolumeClaim `json:"items"`
18 | }
19 |
20 | type PersistentVolumeClaimNp struct {
21 | NameSpace string `json:"namespace"`
22 | PersistentVolumeClaimNum int `json:"PersistentVolumeClaim_num"`
23 | }
24 |
25 | func (d *persistentVolumeClaim) toCells(PersistentVolumeClaims []coreV1.PersistentVolumeClaim) []DataCell {
26 | cells := make([]DataCell, len(PersistentVolumeClaims))
27 | for i := range PersistentVolumeClaims {
28 | cells[i] = persistentVolumeClaimCell(PersistentVolumeClaims[i])
29 | }
30 | return cells
31 | }
32 |
33 | func (d *persistentVolumeClaim) FromCells(cells []DataCell) []coreV1.PersistentVolumeClaim {
34 | PersistentVolumeClaims := make([]coreV1.PersistentVolumeClaim, len(cells))
35 | for i := range cells {
36 | PersistentVolumeClaims[i] = coreV1.PersistentVolumeClaim(cells[i].(persistentVolumeClaimCell))
37 | }
38 | return PersistentVolumeClaims
39 | }
40 |
41 | func (d *persistentVolumeClaim) DeletePersistentVolumeClaim(name, namespace string) error {
42 | return K8s.ClientSet.CoreV1().PersistentVolumeClaims(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
43 | }
44 |
45 | func (d *persistentVolumeClaim) UpdatePersistentVolumeClaim(content, namespace string) error {
46 | var PersistentVolumeClaim = &coreV1.PersistentVolumeClaim{}
47 | if err := json.Unmarshal([]byte(content), PersistentVolumeClaim); err != nil {
48 | return err
49 | }
50 | if _, err := K8s.ClientSet.CoreV1().PersistentVolumeClaims(namespace).Update(context.TODO(), PersistentVolumeClaim, metaV1.UpdateOptions{}); err != nil {
51 | return err
52 | }
53 | return nil
54 | }
55 |
56 | func (d *persistentVolumeClaim) GetPersistentVolumeClaims(filterName, namespace string, limit, page int) (*PersistentVolumeClaimResp, error) {
57 | PersistentVolumeClaimList, err := K8s.ClientSet.CoreV1().PersistentVolumeClaims(namespace).List(context.TODO(), metaV1.ListOptions{})
58 | if err != nil {
59 | return nil, err
60 | }
61 | selectableData := &dataSelector{
62 | GenericDataList: d.toCells(PersistentVolumeClaimList.Items),
63 | DataSelect: &DataSelectQuery{
64 | Filter: &FilterQuery{Name: filterName},
65 | Paginatite: &PaginateQuery{
66 | Limit: limit,
67 | Page: page,
68 | },
69 | },
70 | }
71 | filterd := selectableData.Filter()
72 | total := len(filterd.GenericDataList)
73 | data := filterd.Sort().Paginate()
74 | PersistentVolumeClaims := d.FromCells(data.GenericDataList)
75 | return &PersistentVolumeClaimResp{
76 | Total: total,
77 | Items: PersistentVolumeClaims,
78 | }, nil
79 | }
80 |
81 | func (d *persistentVolumeClaim) GetPersistentVolumeClaimDetail(name, namespace string) (*coreV1.PersistentVolumeClaim, error) {
82 | data, err := K8s.ClientSet.CoreV1().PersistentVolumeClaims(namespace).Get(context.TODO(), name, metaV1.GetOptions{})
83 | if err != nil {
84 | return nil, err
85 | }
86 | return data, nil
87 | }
88 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/persistentvolume.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 |
6 | "github.com/pkg/errors"
7 | coreV1 "k8s.io/api/core/v1"
8 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | var PersistentVolume persistentVolume
12 |
13 | type persistentVolume struct{}
14 |
15 | type PersistentVolumeResp struct {
16 | Total int `json:"total"`
17 | Items []coreV1.PersistentVolume `json:"items"`
18 | }
19 |
20 | func (n *persistentVolume) toCells(pvs []coreV1.PersistentVolume) []DataCell {
21 | cells := make([]DataCell, len(pvs))
22 | for i := range pvs {
23 | cells[i] = persistentvolumesCell(pvs[i])
24 | }
25 | return cells
26 | }
27 |
28 | func (n *persistentVolume) FromCells(cells []DataCell) []coreV1.PersistentVolume {
29 | nodes := make([]coreV1.PersistentVolume, len(cells))
30 | for i := range cells {
31 | nodes[i] = coreV1.PersistentVolume(cells[i].(persistentvolumesCell))
32 | }
33 | return nodes
34 | }
35 |
36 | func (n *persistentVolume) GetPersistentVolumes(filterName string, limit, page int) (*PersistentVolumeResp, error) {
37 | PersistentVolumeList, err := K8s.ClientSet.CoreV1().PersistentVolumes().List(context.TODO(), metaV1.ListOptions{})
38 | if err != nil {
39 | return nil, errors.New("获取Pod列表失败")
40 | }
41 | //实例化dataSelector结构体,组装数据
42 | selectableData := &dataSelector{
43 | GenericDataList: n.toCells(PersistentVolumeList.Items),
44 | DataSelect: &DataSelectQuery{
45 | Filter: &FilterQuery{Name: filterName},
46 | Paginatite: &PaginateQuery{limit, page},
47 | },
48 | }
49 | //先过滤
50 | filtered := selectableData.Filter()
51 | total := len(filtered.GenericDataList)
52 | //排序、分页
53 | data := filtered.Sort().Paginate()
54 | //将dataCell类型转换为coreV1.Pod
55 | PersistentVolumes := n.FromCells(data.GenericDataList)
56 | return &PersistentVolumeResp{
57 | total,
58 | PersistentVolumes,
59 | }, nil
60 | }
61 |
62 | // GetPersistentVolumesDetail 获取PersistentVolume详情
63 | func (n *persistentVolume) GetPersistentVolumesDetail(Name string) (*coreV1.PersistentVolume, error) {
64 | PersistentVolumesRes, err := K8s.ClientSet.CoreV1().PersistentVolumes().Get(context.TODO(), Name, metaV1.GetOptions{})
65 | if err != nil {
66 | return nil, err
67 | }
68 | return PersistentVolumesRes, nil
69 | }
70 |
71 | func (n *persistentVolume) DeletePersistentVolume(name string) error {
72 | return K8s.ClientSet.CoreV1().PersistentVolumes().Delete(context.TODO(), name, metaV1.DeleteOptions{})
73 | }
74 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/pod.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "net/http"
5 |
6 | coreV1 "k8s.io/api/core/v1"
7 | "k8s.io/client-go/kubernetes"
8 | "k8s.io/client-go/kubernetes/scheme"
9 | "k8s.io/client-go/tools/remotecommand"
10 |
11 | "github.com/noovertime7/kubemanage/dao"
12 | "github.com/noovertime7/kubemanage/dto/kubeDto"
13 | "github.com/noovertime7/kubemanage/pkg/logger"
14 | "github.com/noovertime7/kubemanage/pkg/types"
15 | )
16 |
17 | type PodsGetter interface {
18 | Pods(cloud string) PodInterface
19 | }
20 |
21 | type PodInterface interface {
22 | WebShellHandler(webShellOptions *kubeDto.WebShellOptions, w http.ResponseWriter, r *http.Request) error
23 | }
24 |
25 | type pods struct {
26 | client *kubernetes.Clientset
27 | cloud string
28 | factory dao.ShareDaoFactory
29 | }
30 |
31 | func NewPods(c *kubernetes.Clientset, cloud string, factory dao.ShareDaoFactory) *pods {
32 | return &pods{
33 | client: c,
34 | cloud: cloud,
35 | factory: factory,
36 | }
37 | }
38 |
39 | func (c *pods) WebShellHandler(webShellOptions *kubeDto.WebShellOptions, w http.ResponseWriter, r *http.Request) error {
40 | log := logger.New()
41 | session, err := types.NewTerminalSession(w, r)
42 | if err != nil {
43 | return err
44 | }
45 | // 处理关闭
46 | defer func() {
47 | _ = session.Close()
48 | }()
49 |
50 | // 组装 POST 请求
51 | req := K8s.ClientSet.CoreV1().RESTClient().Post().
52 | Resource("pods").
53 | Name(webShellOptions.Pod).
54 | Namespace(webShellOptions.Namespace).
55 | SubResource("exec").
56 | VersionedParams(&coreV1.PodExecOptions{
57 | Container: webShellOptions.Container,
58 | Command: []string{"/bin/sh"},
59 | Stderr: true,
60 | Stdin: true,
61 | Stdout: true,
62 | TTY: true,
63 | }, scheme.ParameterCodec)
64 |
65 | // remotecommand 主要实现了http 转 SPDY 添加X-Stream-Protocol-Version相关header 并发送请求
66 | executor, err := remotecommand.NewSPDYExecutor(K8s.Config, "POST", req.URL())
67 | if err != nil {
68 | log.ErrorWithErr("remotecommand pod error", err)
69 | return err
70 | }
71 | // 与 kubelet 建立 stream 连接
72 | if err = executor.Stream(remotecommand.StreamOptions{
73 | Stdout: session,
74 | Stdin: session,
75 | Stderr: session,
76 | TerminalSizeQueue: session,
77 | Tty: true,
78 | }); err != nil {
79 | log.ErrorWithErr("exec pod error", err)
80 | _, _ = session.Write([]byte("exec pod command failed," + err.Error()))
81 | // 标记关闭terminal
82 | session.Done()
83 | }
84 | return nil
85 | }
86 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/pod_v1.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "bytes"
5 | "context"
6 | "encoding/json"
7 | "io"
8 |
9 | coreV1 "k8s.io/api/core/v1"
10 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 | )
12 |
13 | var Pod pod
14 |
15 | type pod struct{}
16 |
17 | type PodsResp struct {
18 | Total int `json:"total"`
19 | Items []coreV1.Pod `json:"items"`
20 | }
21 |
22 | type PodsNp struct {
23 | Namespace string `json:"namespace"`
24 | PodNum int `json:"pod_num"`
25 | }
26 |
27 | // GetPods 获取pod列表支持、过滤、排序以及分页
28 | func (p *pod) GetPods(filterName, namespace string, limit, page int) (podsResp *PodsResp, err error) {
29 | podlist, err := K8s.ClientSet.CoreV1().Pods(namespace).List(context.TODO(), metaV1.ListOptions{})
30 | if err != nil {
31 | return nil, err
32 | }
33 | //实例化dataSelector结构体,组装数据
34 | selectableData := &dataSelector{
35 | GenericDataList: p.toCells(podlist.Items),
36 | DataSelect: &DataSelectQuery{
37 | Filter: &FilterQuery{Name: filterName},
38 | Paginatite: &PaginateQuery{limit, page},
39 | },
40 | }
41 | //先过滤
42 | filtered := selectableData.Filter()
43 | total := len(filtered.GenericDataList)
44 | //排序、分页
45 | data := filtered.Sort().Paginate()
46 | //将dataCell类型转换为coreV1.Pod
47 | pods := p.FromCells(data.GenericDataList)
48 | return &PodsResp{
49 | total,
50 | pods,
51 | }, nil
52 | }
53 |
54 | // GetPodDetail 获取Pod详情
55 | func (p *pod) GetPodDetail(podName, namespace string) (pod *coreV1.Pod, err error) {
56 | podRes, err := K8s.ClientSet.CoreV1().Pods(namespace).Get(context.TODO(), podName, metaV1.GetOptions{})
57 | if err != nil {
58 | return nil, err
59 | }
60 | return podRes, nil
61 | }
62 |
63 | // DeletePod 删除Pod
64 | func (p *pod) DeletePod(podName, namespace string) error {
65 | err := K8s.ClientSet.CoreV1().Pods(namespace).Delete(context.TODO(), podName, metaV1.DeleteOptions{})
66 | if err != nil {
67 | return err
68 | }
69 | return nil
70 | }
71 |
72 | // UpdatePod 更新Pod
73 | func (p *pod) UpdatePod(namespace, content string) error {
74 | var pod = &coreV1.Pod{}
75 | //将json反序列换为pod类型
76 | if err := json.Unmarshal([]byte(content), pod); err != nil {
77 | return err
78 | }
79 | _, err := K8s.ClientSet.CoreV1().Pods(namespace).Update(context.TODO(), pod, metaV1.UpdateOptions{})
80 | if err != nil {
81 | return err
82 | }
83 | return nil
84 | }
85 |
86 | // GetPodContainer 获取Pod容器名
87 | func (p *pod) GetPodContainer(podName, namespace string) (containers []string, err error) {
88 | pod, err := p.GetPodDetail(podName, namespace)
89 | if err != nil {
90 | return nil, err
91 | }
92 | //从pod中获取containers
93 | for _, container := range pod.Spec.Containers {
94 | containers = append(containers, container.Name)
95 | }
96 | return containers, nil
97 | }
98 |
99 | // GetPodLog 获取容器日志
100 | func (p *pod) GetPodLog(containerName, podName, namespace string) (log string, err error) {
101 | //设置日志的配置,容器名,获取的内容的配置
102 | lineLimit := int64(100)
103 | op := &coreV1.PodLogOptions{
104 | Container: containerName,
105 | TailLines: &lineLimit,
106 | }
107 | //获取request的实例
108 | req := K8s.ClientSet.CoreV1().Pods(namespace).GetLogs(podName, op)
109 | //发起stream连接,得到response.body
110 | podLogs, err := req.Stream(context.TODO())
111 | if err != nil {
112 | return "", err
113 | }
114 | defer func(podLogs io.ReadCloser) {
115 | err := podLogs.Close()
116 | if err != nil {
117 |
118 | }
119 | }(podLogs)
120 | //将body写入缓冲区,转换为可读的string类型
121 | buf := new(bytes.Buffer)
122 | if _, err := io.Copy(buf, podLogs); err != nil {
123 | return "", err
124 | }
125 | return buf.String(), nil
126 | }
127 |
128 | // GetPodNumPerNp 获取namespace下的Pod数量
129 | func (p *pod) GetPodNumPerNp() (podsNps []*PodsNp, err error) {
130 | namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metaV1.ListOptions{})
131 | if err != nil {
132 | return nil, err
133 | }
134 | for _, namespace := range namespaceList.Items {
135 | podList, err := K8s.ClientSet.CoreV1().Pods(namespace.Name).List(context.TODO(), metaV1.ListOptions{})
136 | if err != nil {
137 | return nil, err
138 | }
139 | //组装数据
140 | podsNp := &PodsNp{
141 | Namespace: namespace.Name,
142 | PodNum: len(podList.Items),
143 | }
144 | podsNps = append(podsNps, podsNp)
145 | }
146 | return podsNps, nil
147 | }
148 |
149 | // 类型转换的方法 coreV1.pod => DataCell,DataCell => coreV1.pod
150 | func (p *pod) toCells(pods []coreV1.Pod) []DataCell {
151 | cells := make([]DataCell, len(pods))
152 | for i := range pods {
153 | cells[i] = podCell(pods[i])
154 | }
155 | return cells
156 | }
157 |
158 | func (p *pod) FromCells(cells []DataCell) []coreV1.Pod {
159 | pods := make([]coreV1.Pod, len(cells))
160 | for i := range cells {
161 | pods[i] = coreV1.Pod(cells[i].(podCell))
162 | }
163 | return pods
164 | }
165 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/secret.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 |
7 | coreV1 "k8s.io/api/core/v1"
8 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | )
10 |
11 | var Secret secret
12 |
13 | type secret struct {
14 | }
15 |
16 | type SecretResp struct {
17 | Total int `json:"total"`
18 | Items []coreV1.Secret `json:"items"`
19 | }
20 |
21 | type SecretNp struct {
22 | NameSpace string `json:"namespace"`
23 | SecretNum int `json:"secret_num"`
24 | }
25 |
26 | func (d *secret) toCells(secrets []coreV1.Secret) []DataCell {
27 | cells := make([]DataCell, len(secrets))
28 | for i := range secrets {
29 | cells[i] = secretCell(secrets[i])
30 | }
31 | return cells
32 | }
33 |
34 | func (d *secret) FromCells(cells []DataCell) []coreV1.Secret {
35 | secrets := make([]coreV1.Secret, len(cells))
36 | for i := range cells {
37 | secrets[i] = coreV1.Secret(cells[i].(secretCell))
38 | }
39 | return secrets
40 | }
41 |
42 | func (d *secret) GetSecrets(filterName, namespace string, limit, page int) (*SecretResp, error) {
43 | SecretsList, err := K8s.ClientSet.CoreV1().Secrets(namespace).List(context.TODO(), metaV1.ListOptions{})
44 | if err != nil {
45 | return nil, err
46 | }
47 | selectableData := &dataSelector{
48 | GenericDataList: d.toCells(SecretsList.Items),
49 | DataSelect: &DataSelectQuery{
50 | Filter: &FilterQuery{Name: filterName},
51 | Paginatite: &PaginateQuery{
52 | Limit: limit,
53 | Page: page,
54 | },
55 | },
56 | }
57 | filterd := selectableData.Filter()
58 | total := len(filterd.GenericDataList)
59 | data := filterd.Sort().Paginate()
60 | secrets := d.FromCells(data.GenericDataList)
61 | return &SecretResp{
62 | Total: total,
63 | Items: secrets,
64 | }, nil
65 | }
66 |
67 | func (d *secret) GetSecretsDetail(name, namespace string) (*coreV1.Secret, error) {
68 | data, err := K8s.ClientSet.CoreV1().Secrets(namespace).Get(context.TODO(), name, metaV1.GetOptions{})
69 | if err != nil {
70 | return nil, err
71 | }
72 | return data, nil
73 | }
74 |
75 | func (d *secret) DeleteSecrets(name, namespace string) error {
76 | return K8s.ClientSet.CoreV1().Secrets(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
77 | }
78 |
79 | func (d *secret) UpdateSecrets(content, namespace string) error {
80 | var secret = &coreV1.Secret{}
81 | if err := json.Unmarshal([]byte(content), secret); err != nil {
82 | return err
83 | }
84 | if _, err := K8s.ClientSet.CoreV1().Secrets(namespace).Update(context.TODO(), secret, metaV1.UpdateOptions{}); err != nil {
85 | return err
86 | }
87 | return nil
88 | }
89 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/service.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 |
7 | coreV1 "k8s.io/api/core/v1"
8 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
9 | "k8s.io/apimachinery/pkg/util/intstr"
10 |
11 | "github.com/noovertime7/kubemanage/dto/kubeDto"
12 | )
13 |
14 | var Service service
15 |
16 | type service struct{}
17 |
18 | type serviceResp struct {
19 | Total int `json:"total"`
20 | Items []coreV1.Service `json:"items"`
21 | }
22 |
23 | type serviceNp struct {
24 | NameSpace string `json:"namespace"`
25 | ServiceNum int `json:"service_num"`
26 | }
27 |
28 | func (s *service) toCells(services []coreV1.Service) []DataCell {
29 | cells := make([]DataCell, len(services))
30 | for i := range services {
31 | cells[i] = serviceCell(services[i])
32 | }
33 | return cells
34 | }
35 |
36 | func (s *service) FromCells(cells []DataCell) []coreV1.Service {
37 | services := make([]coreV1.Service, len(cells))
38 | for i := range cells {
39 | services[i] = coreV1.Service(cells[i].(serviceCell))
40 | }
41 | return services
42 | }
43 |
44 | func (s *service) CreateService(data *kubeDto.ServiceCreateInput) error {
45 | service := &coreV1.Service{
46 | ObjectMeta: metaV1.ObjectMeta{
47 | Name: data.Name,
48 | Namespace: data.NameSpace,
49 | Labels: data.Label,
50 | },
51 | Spec: coreV1.ServiceSpec{
52 | Type: coreV1.ServiceType(data.Type),
53 | Ports: []coreV1.ServicePort{
54 | {
55 | Name: "http",
56 | Port: data.Port,
57 | Protocol: "TCP",
58 | TargetPort: intstr.IntOrString{
59 | Type: 0,
60 | IntVal: data.ContainerPort,
61 | },
62 | },
63 | },
64 | Selector: data.Label,
65 | },
66 | Status: coreV1.ServiceStatus{},
67 | }
68 | if data.NodePort != 0 && data.Type == "NodePort" {
69 | service.Spec.Ports[0].NodePort = data.NodePort
70 | }
71 | //创建service
72 | if _, err := K8s.ClientSet.CoreV1().Services(data.NameSpace).Create(context.TODO(), service, metaV1.CreateOptions{}); err != nil {
73 | return err
74 | }
75 | return nil
76 | }
77 |
78 | func (s *service) DeleteService(name, namespace string) error {
79 | return K8s.ClientSet.CoreV1().Services(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
80 | }
81 |
82 | func (s *service) UpdateService(namespace, content string) error {
83 | var Service = &coreV1.Service{}
84 | if err := json.Unmarshal([]byte(content), Service); err != nil {
85 | return err
86 | }
87 | if _, err := K8s.ClientSet.CoreV1().Services(namespace).Update(context.TODO(), Service, metaV1.UpdateOptions{}); err != nil {
88 | return err
89 | }
90 | return nil
91 | }
92 |
93 | func (s *service) GetServiceList(filterName, namespace string, limit, page int) (*serviceResp, error) {
94 | ServiceList, err := K8s.ClientSet.CoreV1().Services(namespace).List(context.TODO(), metaV1.ListOptions{})
95 | if err != nil {
96 | return nil, err
97 | }
98 | //实例化dataSelector结构体,组装数据
99 | selectableData := &dataSelector{
100 | GenericDataList: s.toCells(ServiceList.Items),
101 | DataSelect: &DataSelectQuery{
102 | Filter: &FilterQuery{Name: filterName},
103 | Paginatite: &PaginateQuery{limit, page},
104 | },
105 | }
106 | //先过滤
107 | filtered := selectableData.Filter()
108 | total := len(filtered.GenericDataList)
109 | //排序、分页
110 | data := filtered.Sort().Paginate()
111 | //将dataCell类型转换为coreV1.Pod
112 | Services := s.FromCells(data.GenericDataList)
113 | return &serviceResp{
114 | total,
115 | Services,
116 | }, nil
117 | }
118 |
119 | func (s *service) GetServiceDetail(name, namespace string) (*coreV1.Service, error) {
120 | data, err := K8s.ClientSet.CoreV1().Services(namespace).Get(context.TODO(), name, metaV1.GetOptions{})
121 | if err != nil {
122 | return nil, err
123 | }
124 | return data, nil
125 | }
126 |
127 | func (s *service) GetServiceNp() ([]*serviceNp, error) {
128 | namespaceList, err := K8s.ClientSet.CoreV1().Namespaces().List(context.TODO(), metaV1.ListOptions{})
129 | if err != nil {
130 | return nil, err
131 | }
132 | var services []*serviceNp
133 | for _, namespace := range namespaceList.Items {
134 | serviceList, err := K8s.ClientSet.CoreV1().Services(namespace.Name).List(context.TODO(), metaV1.ListOptions{})
135 | if err != nil {
136 | return nil, err
137 | }
138 | //组装数据
139 | ServiceNp := &serviceNp{
140 | NameSpace: namespace.Name,
141 | ServiceNum: len(serviceList.Items),
142 | }
143 | services = append(services, ServiceNp)
144 | }
145 | return services, nil
146 | }
147 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/kube/statefulset.go:
--------------------------------------------------------------------------------
1 | package kube
2 |
3 | import (
4 | "context"
5 | "encoding/json"
6 | appsV1 "k8s.io/api/apps/v1"
7 | metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
8 | )
9 |
10 | var StatefulSet statefulSet
11 |
12 | type statefulSet struct{}
13 |
14 | type statefulSetResp struct {
15 | Total int `json:"total"`
16 | Items []appsV1.StatefulSet `json:"items"`
17 | }
18 |
19 | type StatefulSetNp struct {
20 | NameSpace string `json:"namespace"`
21 | DaemonSetNum int `json:"daemonset_num"`
22 | }
23 |
24 | func (d *statefulSet) toCells(statefulSets []appsV1.StatefulSet) []DataCell {
25 | cells := make([]DataCell, len(statefulSets))
26 | for i := range statefulSets {
27 | cells[i] = statefulSetCell(statefulSets[i])
28 | }
29 | return cells
30 | }
31 |
32 | func (d *statefulSet) FromCells(cells []DataCell) []appsV1.StatefulSet {
33 | statefulSets := make([]appsV1.StatefulSet, len(cells))
34 | for i := range cells {
35 | statefulSets[i] = appsV1.StatefulSet(cells[i].(statefulSetCell))
36 | }
37 | return statefulSets
38 | }
39 |
40 | func (d *statefulSet) GetStatefulSets(filterName, namespace string, limit, page int) (*statefulSetResp, error) {
41 | statefulSetList, err := K8s.ClientSet.AppsV1().StatefulSets(namespace).List(context.TODO(), metaV1.ListOptions{})
42 | if err != nil {
43 | return nil, err
44 | }
45 | selectableData := &dataSelector{
46 | GenericDataList: d.toCells(statefulSetList.Items),
47 | DataSelect: &DataSelectQuery{
48 | Filter: &FilterQuery{Name: filterName},
49 | Paginatite: &PaginateQuery{
50 | Limit: limit,
51 | Page: page,
52 | },
53 | },
54 | }
55 | filterd := selectableData.Filter()
56 | total := len(filterd.GenericDataList)
57 | data := filterd.Sort().Paginate()
58 | statefulSets := d.FromCells(data.GenericDataList)
59 | return &statefulSetResp{
60 | Total: total,
61 | Items: statefulSets,
62 | }, nil
63 | }
64 |
65 | func (d *statefulSet) GetStatefulSetDetail(name, namespace string) (*appsV1.StatefulSet, error) {
66 | data, err := K8s.ClientSet.AppsV1().StatefulSets(namespace).Get(context.TODO(), name, metaV1.GetOptions{})
67 | if err != nil {
68 | return nil, err
69 | }
70 | return data, nil
71 | }
72 |
73 | func (d *statefulSet) DeleteStatefulSet(name, namespace string) error {
74 | return K8s.ClientSet.AppsV1().StatefulSets(namespace).Delete(context.TODO(), name, metaV1.DeleteOptions{})
75 | }
76 |
77 | func (d *statefulSet) UpdateStatefulSet(content, namespace string) error {
78 | var statefulSet = &appsV1.StatefulSet{}
79 | if err := json.Unmarshal([]byte(content), statefulSet); err != nil {
80 | return err
81 | }
82 | if _, err := K8s.ClientSet.AppsV1().StatefulSets(namespace).Update(context.TODO(), statefulSet, metaV1.UpdateOptions{}); err != nil {
83 | return err
84 | }
85 | return nil
86 | }
87 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/setup.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/noovertime7/kubemanage/cmd/app/config"
5 | "github.com/noovertime7/kubemanage/cmd/app/options"
6 | "github.com/noovertime7/kubemanage/pkg/logger"
7 | )
8 |
9 | var CoreV1 CoreService
10 |
11 | var Log Logger
12 |
13 | // Setup 完成核心应用接口的设置
14 | func Setup(o *options.Options) {
15 | Log = logger.New()
16 | CoreV1 = New(config.SysConfig, o.Factory)
17 | }
18 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/sys/api.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao"
6 | "github.com/noovertime7/kubemanage/dao/model"
7 | )
8 |
9 | type APIServiceGetter interface {
10 | Api() APIService
11 | }
12 |
13 | type APIService interface {
14 | GetApiList(ctx context.Context) ([]model.SysApi, error)
15 | }
16 |
17 | var _ APIService = &apiService{}
18 |
19 | func NewApiService(factory dao.ShareDaoFactory) APIService {
20 | return &apiService{factory: factory}
21 | }
22 |
23 | type apiService struct {
24 | factory dao.ShareDaoFactory
25 | }
26 |
27 | func (a *apiService) GetApiList(ctx context.Context) ([]model.SysApi, error) {
28 | // 不做任何限制查询全量数据
29 | var search model.SysApi
30 | return a.factory.Api().FindList(ctx, search)
31 | }
32 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/sys/authority.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dto"
6 |
7 | "github.com/noovertime7/kubemanage/dao"
8 | "github.com/noovertime7/kubemanage/dao/model"
9 | )
10 |
11 | type AuthorityGetter interface {
12 | Authority() Authority
13 | }
14 |
15 | type Authority interface {
16 | SetMenuAuthority(ctx context.Context, auth *model.SysAuthority) error
17 | GetAuthorityList(ctx context.Context, pageInfo dto.PageInfo) (*dto.AuthorityList, error)
18 | }
19 |
20 | type authority struct {
21 | factory dao.ShareDaoFactory
22 | }
23 |
24 | func NewAuthority(factory dao.ShareDaoFactory) *authority {
25 | return &authority{factory: factory}
26 | }
27 |
28 | func (a *authority) SetMenuAuthority(ctx context.Context, auth *model.SysAuthority) error {
29 | return a.factory.Authority().SetMenuAuthority(ctx, auth)
30 | }
31 |
32 | func (a *authority) GetAuthorityList(ctx context.Context, pageInfo dto.PageInfo) (*dto.AuthorityList, error) {
33 | list, total, err := a.factory.Authority().PageList(ctx, pageInfo)
34 | if err != nil {
35 | return nil, err
36 | }
37 | return &dto.AuthorityList{
38 | PageInfo: pageInfo,
39 | Total: total,
40 | AuthorityListItem: list,
41 | }, nil
42 | }
43 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/sys/casbin.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "strconv"
5 | "sync"
6 |
7 | "github.com/casbin/casbin/v2"
8 | "github.com/casbin/casbin/v2/model"
9 | gormadapter "github.com/casbin/gorm-adapter/v3"
10 | "github.com/pkg/errors"
11 |
12 | "github.com/noovertime7/kubemanage/dao"
13 | "github.com/noovertime7/kubemanage/dto"
14 | )
15 |
16 | type CasbinServiceGetter interface {
17 | CasbinService() CasbinService
18 | }
19 |
20 | type CasbinService interface {
21 | UpdateCasbin(AuthorityID uint, casbinInfos []dto.CasbinInfo) error
22 | UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error
23 | GetPolicyPathByAuthorityId(AuthorityID uint) (pathMaps []dto.CasbinInfo)
24 | Casbin() *casbin.CachedEnforcer
25 | }
26 |
27 | type casbinService struct {
28 | factory dao.ShareDaoFactory
29 | }
30 |
31 | func NewCasbinService(factory dao.ShareDaoFactory) CasbinService {
32 | return &casbinService{factory: factory}
33 | }
34 |
35 | func (c *casbinService) UpdateCasbin(AuthorityID uint, casbinInfos []dto.CasbinInfo) error {
36 | authorityId := strconv.Itoa(int(AuthorityID))
37 | c.ClearCasbin(0, authorityId)
38 | var rules [][]string
39 | for _, v := range casbinInfos {
40 | rules = append(rules, []string{authorityId, v.Path, v.Method})
41 | }
42 | e := c.Casbin()
43 | success, _ := e.AddPolicies(rules)
44 | if !success {
45 | return errors.New("存在相同api,添加失败,请联系管理员")
46 | }
47 | err := e.InvalidateCache()
48 | if err != nil {
49 | return err
50 | }
51 | return nil
52 | }
53 |
54 | func (c *casbinService) UpdateCasbinApi(oldPath string, newPath string, oldMethod string, newMethod string) error {
55 | err := c.factory.GetDB().Model(&gormadapter.CasbinRule{}).Where("v1 = ? AND v2 = ?", oldPath, oldMethod).Updates(map[string]interface{}{
56 | "v1": newPath,
57 | "v2": newMethod,
58 | }).Error
59 | e := c.Casbin()
60 | err = e.InvalidateCache()
61 | if err != nil {
62 | return err
63 | }
64 | return err
65 | }
66 |
67 | func (c *casbinService) GetPolicyPathByAuthorityId(AuthorityID uint) (pathMaps []dto.CasbinInfo) {
68 | e := c.Casbin()
69 | authorityId := strconv.Itoa(int(AuthorityID))
70 | list := e.GetFilteredPolicy(0, authorityId)
71 | for _, v := range list {
72 | pathMaps = append(pathMaps, dto.CasbinInfo{
73 | Path: v[1],
74 | Method: v[2],
75 | })
76 | }
77 | return pathMaps
78 | }
79 |
80 | func (c *casbinService) ClearCasbin(v int, p ...string) bool {
81 | e := c.Casbin()
82 | success, _ := e.RemoveFilteredPolicy(v, p...)
83 | return success
84 | }
85 |
86 | var (
87 | cachedEnforcer *casbin.CachedEnforcer
88 | once sync.Once
89 | )
90 |
91 | func (c *casbinService) Casbin() *casbin.CachedEnforcer {
92 | once.Do(func() {
93 | a, _ := gormadapter.NewAdapterByDB(c.factory.GetDB())
94 | text := `
95 | [request_definition]
96 | r = sub, obj, act
97 |
98 | [policy_definition]
99 | p = sub, obj, act
100 |
101 | [role_definition]
102 | g = _, _
103 |
104 | [policy_effect]
105 | e = some(where (p.eft == allow))
106 |
107 | [matchers]
108 | m = g(r.sub, p.sub) && keyMatch2(r.obj, p.obj) && regexMatch(r.act, p.act) || r.sub == "111"
109 | `
110 | m, err := model.NewModelFromString(text)
111 | if err != nil {
112 | return
113 | }
114 | cachedEnforcer, _ = casbin.NewCachedEnforcer(m, a)
115 | cachedEnforcer.SetExpireTime(60 * 60)
116 | _ = cachedEnforcer.LoadPolicy()
117 | })
118 | return cachedEnforcer
119 | }
120 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/sys/menu.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "context"
5 | "strconv"
6 |
7 | "github.com/pkg/errors"
8 | "gorm.io/gorm"
9 |
10 | "github.com/noovertime7/kubemanage/dao"
11 | "github.com/noovertime7/kubemanage/dao/model"
12 | "github.com/noovertime7/kubemanage/dto"
13 | )
14 |
15 | type MenuGetter interface {
16 | Menu() MenuService
17 | }
18 |
19 | type MenuService interface {
20 | GetMenuByAuthorityID(ctx context.Context, authorityId uint) ([]model.SysMenu, error)
21 | GetBassMenu(ctx context.Context) ([]model.SysBaseMenu, error)
22 | AddBaseMenu(ctx context.Context, in *dto.AddSysMenusInput) error
23 | AddMenuAuthority(ctx context.Context, menus []model.SysBaseMenu, authorityId uint) error
24 | }
25 |
26 | type menuService struct {
27 | factory dao.ShareDaoFactory
28 | }
29 |
30 | func NewMenuService(factory dao.ShareDaoFactory) *menuService {
31 | return &menuService{factory: factory}
32 | }
33 |
34 | // GetBassMenu 获取全量的菜单
35 | func (m *menuService) GetBassMenu(ctx context.Context) ([]model.SysBaseMenu, error) {
36 | treeMap, err := m.getBaseMenuTreeMap(ctx)
37 | if err != nil {
38 | return nil, err
39 | }
40 | menus := treeMap["0"]
41 | for i := 0; i < len(menus); i++ {
42 | if err := m.getBaseChildrenList(&menus[i], treeMap); err != nil {
43 | return nil, err
44 | }
45 | }
46 | return menus, nil
47 | }
48 |
49 | func (m *menuService) GetMenuByAuthorityID(ctx context.Context, authorityId uint) ([]model.SysMenu, error) {
50 | menuTree, err := m.getMenuTree(ctx, authorityId)
51 | if err != nil {
52 | return nil, err
53 | }
54 | //parent_id = 0 ,代表所有跟路由
55 | menus := menuTree["0"]
56 | for i := 0; i < len(menus); i++ {
57 | err = m.getChildrenList(&menus[i], menuTree)
58 | }
59 | return menus, nil
60 | }
61 |
62 | // AddBaseMenu 添加基础路由
63 | func (m *menuService) AddBaseMenu(ctx context.Context, in *dto.AddSysMenusInput) error {
64 | menuInfo := &model.SysBaseMenu{
65 | ParentId: in.ParentId,
66 | Name: in.Name,
67 | Path: in.Path,
68 | Hidden: in.Hidden,
69 | Sort: in.Sort,
70 | Meta: in.Meta,
71 | }
72 | menu, err := m.factory.BaseMenu().Find(ctx, menuInfo)
73 | if !errors.Is(err, gorm.ErrRecordNotFound) && menu.ID != 0 {
74 | return errors.New("存在重复名称菜单,请修改菜单名称")
75 | }
76 | return m.factory.BaseMenu().Save(ctx, menuInfo)
77 | }
78 |
79 | // AddMenuAuthority 为角色增加menu树
80 | func (m *menuService) AddMenuAuthority(ctx context.Context, menus []model.SysBaseMenu, authorityId uint) error {
81 | auth := &model.SysAuthority{AuthorityId: authorityId, SysBaseMenus: menus}
82 | return m.factory.Authority().SetMenuAuthority(ctx, auth)
83 | }
84 |
85 | func (m *menuService) getMenuTree(ctx context.Context, authorityId uint) (map[string][]model.SysMenu, error) {
86 | var allMenus []model.SysMenu
87 | treeMap := make(map[string][]model.SysMenu)
88 | SysAuthorityMenu := &model.SysAuthorityMenu{AuthorityId: strconv.Itoa(int(authorityId))}
89 | authorityMenus, err := m.factory.AuthorityMenu().FindList(ctx, SysAuthorityMenu)
90 | if err != nil {
91 | return nil, err
92 | }
93 | var MenuIds []string
94 | for i := range authorityMenus {
95 | MenuIds = append(MenuIds, authorityMenus[i].MenuId)
96 | }
97 | baseMenus, err := m.factory.BaseMenu().FindIn(ctx, MenuIds)
98 | if err != nil {
99 | return nil, err
100 | }
101 | for i := range baseMenus {
102 | allMenus = append(allMenus, model.SysMenu{
103 | SysBaseMenu: *baseMenus[i],
104 | AuthorityId: authorityId,
105 | MenuId: strconv.Itoa(baseMenus[i].ID),
106 | })
107 | }
108 | for _, v := range allMenus {
109 | treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
110 | }
111 | return treeMap, nil
112 | }
113 |
114 | func (m *menuService) getChildrenList(menu *model.SysMenu, treeMap map[string][]model.SysMenu) error {
115 | // treeMap中包含所有路由
116 | menu.Children = treeMap[menu.MenuId]
117 | for i := 0; i < len(menu.Children); i++ {
118 | if err := m.getChildrenList(&menu.Children[i], treeMap); err != nil {
119 | return err
120 | }
121 | }
122 | return nil
123 | }
124 |
125 | func (m *menuService) getBaseChildrenList(menu *model.SysBaseMenu, treeMap map[string][]model.SysBaseMenu) (err error) {
126 | menu.Children = treeMap[strconv.Itoa(menu.ID)]
127 | for i := 0; i < len(menu.Children); i++ {
128 | err = m.getBaseChildrenList(&menu.Children[i], treeMap)
129 | }
130 | return err
131 | }
132 |
133 | func (m *menuService) getBaseMenuTreeMap(ctx context.Context) (treeMap map[string][]model.SysBaseMenu, err error) {
134 | var menuDB *model.SysBaseMenu
135 | treeMap = make(map[string][]model.SysBaseMenu)
136 | allMenus, err := m.factory.BaseMenu().FindList(ctx, menuDB)
137 | if err != nil {
138 | return nil, err
139 | }
140 | for _, v := range allMenus {
141 | treeMap[v.ParentId] = append(treeMap[v.ParentId], v)
142 | }
143 | return treeMap, err
144 | }
145 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/sys/operation.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/dao"
7 | "github.com/noovertime7/kubemanage/dao/model"
8 | "github.com/noovertime7/kubemanage/dto"
9 | )
10 |
11 | type OperationServiceGetter interface {
12 | Operation() OperationService
13 | }
14 |
15 | type OperationService interface {
16 | CreateOperationRecord(ctx *gin.Context, record *model.SysOperationRecord) error
17 | DeleteRecord(ctx *gin.Context, id int) error
18 | DeleteRecords(ctx *gin.Context, ids []int) error
19 | GetPageList(ctx *gin.Context, in *dto.OperationListInput) (*dto.OperationListOutPut, error)
20 | }
21 |
22 | type operationService struct {
23 | factory dao.ShareDaoFactory
24 | }
25 |
26 | func NewOperationService(factory dao.ShareDaoFactory) *operationService {
27 | return &operationService{factory: factory}
28 | }
29 |
30 | func (o *operationService) CreateOperationRecord(ctx *gin.Context, record *model.SysOperationRecord) error {
31 | return o.factory.Opera().Save(ctx, record)
32 | }
33 |
34 | func (o *operationService) DeleteRecord(ctx *gin.Context, id int) error {
35 | record := &model.SysOperationRecord{ID: id}
36 | return o.factory.Opera().Delete(ctx, record)
37 | }
38 |
39 | func (o *operationService) DeleteRecords(ctx *gin.Context, ids []int) error {
40 | return o.factory.Opera().DeleteList(ctx, ids)
41 | }
42 |
43 | func (o *operationService) GetPageList(ctx *gin.Context, in *dto.OperationListInput) (*dto.OperationListOutPut, error) {
44 | list, total, err := o.factory.Opera().PageList(ctx, in)
45 | if err != nil {
46 | return nil, err
47 | }
48 | return &dto.OperationListOutPut{OperationList: list, Total: total, PageInfo: in.PageInfo}, nil
49 | }
50 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/sys/user.go:
--------------------------------------------------------------------------------
1 | package sys
2 |
3 | import (
4 | "database/sql"
5 | "github.com/gin-gonic/gin"
6 |
7 | "github.com/noovertime7/kubemanage/dao"
8 | "github.com/noovertime7/kubemanage/dao/model"
9 | "github.com/noovertime7/kubemanage/dto"
10 | "github.com/noovertime7/kubemanage/pkg"
11 | "github.com/pkg/errors"
12 | )
13 |
14 | type UserServiceGetter interface {
15 | User() UserService
16 | }
17 |
18 | type UserService interface {
19 | Login(ctx *gin.Context, userInfo *dto.AdminLoginInput) (string, error)
20 | LoginOut(ctx *gin.Context, uid int) error
21 | GetUserInfo(ctx *gin.Context, uid int, aid uint) (*dto.UserInfoOut, error)
22 | SetUserAuth(ctx *gin.Context, uid int, aid uint) error
23 | DeleteUser(ctx *gin.Context, uid int) error
24 | ChangePassword(ctx *gin.Context, uid int, info *dto.ChangeUserPwdInput) error
25 | ResetPassword(ctx *gin.Context, uid int) error
26 | }
27 |
28 | type userService struct {
29 | Menu MenuService
30 | Casbin CasbinService
31 | factory dao.ShareDaoFactory
32 | }
33 |
34 | func NewUserService(factory dao.ShareDaoFactory) *userService {
35 | return &userService{
36 | factory: factory,
37 | Menu: NewMenuService(factory),
38 | Casbin: NewCasbinService(factory),
39 | }
40 | }
41 |
42 | var _ UserService = &userService{}
43 |
44 | func (u *userService) Login(ctx *gin.Context, userInfo *dto.AdminLoginInput) (string, error) {
45 | user, err := u.factory.User().Find(ctx, &model.SysUser{UserName: userInfo.UserName})
46 | if err != nil {
47 | return "", err
48 | }
49 |
50 | if !pkg.CheckPassword(userInfo.Password, user.Password) {
51 | return "", errors.New("密码错误,请重新输入")
52 | }
53 |
54 | token, err := pkg.JWTToken.GenerateToken(pkg.BaseClaims{
55 | UUID: user.UUID,
56 | ID: user.ID,
57 | Username: user.UserName,
58 | NickName: user.NickName,
59 | AuthorityId: user.AuthorityId,
60 | })
61 | if err != nil {
62 | return "", err
63 | }
64 | return token, nil
65 | }
66 |
67 | func (u *userService) LoginOut(ctx *gin.Context, uid int) error {
68 | user := &model.SysUser{ID: uid, Status: sql.NullInt64{Int64: 0, Valid: true}}
69 | return u.factory.User().Updates(ctx, user)
70 | }
71 |
72 | func (u *userService) GetUserInfo(ctx *gin.Context, uid int, aid uint) (*dto.UserInfoOut, error) {
73 | user, err := u.factory.User().Find(ctx, &model.SysUser{ID: uid})
74 | if err != nil {
75 | return nil, err
76 | }
77 | menus, err := u.Menu.GetMenuByAuthorityID(ctx, aid)
78 | if err != nil {
79 | return nil, err
80 | }
81 | var outRules []string
82 | rules := u.Casbin.GetPolicyPathByAuthorityId(aid)
83 | for _, rule := range rules {
84 | item := rule.Path + "," + rule.Method
85 | outRules = append(outRules, item)
86 | }
87 | return &dto.UserInfoOut{
88 | User: *user,
89 | Menus: menus,
90 | RuleNames: outRules,
91 | }, nil
92 | }
93 |
94 | func (u *userService) SetUserAuth(ctx *gin.Context, uid int, aid uint) error {
95 | user := &model.SysUser{ID: uid, AuthorityId: aid}
96 | return u.factory.User().Updates(ctx, user)
97 | }
98 |
99 | func (u *userService) DeleteUser(ctx *gin.Context, uid int) error {
100 | user := &model.SysUser{ID: uid}
101 | return u.factory.User().Delete(ctx, user)
102 | }
103 |
104 | func (u *userService) ChangePassword(ctx *gin.Context, uid int, info *dto.ChangeUserPwdInput) error {
105 | userDB := &model.SysUser{ID: uid}
106 | user, err := u.factory.User().Find(ctx, userDB)
107 | if err != nil {
108 | return err
109 | }
110 |
111 | if !pkg.CheckPassword(info.OldPwd, user.Password) {
112 | return errors.New("原密码错误,请重新输入")
113 | }
114 |
115 | //生成新密码
116 | user.Password, err = pkg.GenSaltPassword(info.NewPwd)
117 | if err != nil {
118 | return err
119 | }
120 | return u.factory.User().Updates(ctx, user)
121 | }
122 |
123 | func (u *userService) ResetPassword(ctx *gin.Context, uid int) error {
124 | newPwd, err := pkg.GenSaltPassword("kubemanage")
125 | if err != nil {
126 | return err
127 | }
128 | user := &model.SysUser{ID: uid, Password: newPwd}
129 | return u.factory.User().Updates(ctx, user)
130 | }
131 |
--------------------------------------------------------------------------------
/pkg/core/kubemanage/v1/system.go:
--------------------------------------------------------------------------------
1 | package v1
2 |
3 | import (
4 | "github.com/noovertime7/kubemanage/dao"
5 | "github.com/noovertime7/kubemanage/pkg/core/kubemanage/v1/sys"
6 | )
7 |
8 | type SystemGetter interface {
9 | System() SystemInterface
10 | }
11 |
12 | // SystemInterface 顶层抽象 包括系统相关接口
13 | type SystemInterface interface {
14 | sys.UserServiceGetter
15 | sys.MenuGetter
16 | sys.CasbinServiceGetter
17 | sys.AuthorityGetter
18 | sys.OperationServiceGetter
19 | sys.APIServiceGetter
20 | }
21 |
22 | var _ SystemInterface = &system{}
23 |
24 | func NewSystem(app *KubeManage) SystemInterface {
25 | return &system{app: app, factory: app.Factory}
26 | }
27 |
28 | type system struct {
29 | app *KubeManage
30 | factory dao.ShareDaoFactory
31 | }
32 |
33 | func (s *system) User() sys.UserService {
34 | return sys.NewUserService(s.factory)
35 | }
36 |
37 | func (s *system) Menu() sys.MenuService {
38 | return sys.NewMenuService(s.factory)
39 | }
40 |
41 | func (s *system) CasbinService() sys.CasbinService {
42 | return sys.NewCasbinService(s.factory)
43 | }
44 |
45 | func (s *system) Authority() sys.Authority {
46 | return sys.NewAuthority(s.factory)
47 | }
48 |
49 | func (s *system) Operation() sys.OperationService {
50 | return sys.NewOperationService(s.factory)
51 | }
52 |
53 | func (s *system) Api() sys.APIService {
54 | return sys.NewApiService(s.factory)
55 | }
56 |
--------------------------------------------------------------------------------
/pkg/globalError/global_error.go:
--------------------------------------------------------------------------------
1 | package globalError
2 |
3 | type GlobalError struct {
4 | Code int `json:"code"` // 业务码
5 | Message string `json:"message"` // 业务码
6 | RealErrorMessage string `json:"err_msg"`
7 | }
8 |
9 | func (e *GlobalError) Error() string {
10 | return e.Message
11 | }
12 |
13 | // 2、定义errorCode
14 | const (
15 | AuthErr = 405
16 |
17 | ServerError = 10101 // Internal Server Error
18 | ParamBindError = 10102 // 参数信息有误
19 | AuthorizationError = 10103 // 签名信息有误
20 | CallHTTPError = 10104 // 调用第三方HTTP接口失败
21 | ResubmitMsg = 10105 // 请勿重复提交
22 |
23 | GetError = 20101
24 | CreateError = 20102
25 | DeleteError = 20103
26 | UpdateError = 20104
27 |
28 | LoginErr = 30101
29 | LogoutErr = 30102
30 | )
31 |
32 | // 3、定义errorCode对应的文本信息
33 | var codeTag = map[int]string{
34 | AuthErr: "权限不足,请联系管理员",
35 |
36 | ServerError: "Internal Server Error",
37 | ParamBindError: "参数信息有误",
38 | AuthorizationError: "签名信息有误",
39 | CallHTTPError: "调用第三方 HTTP 接口失败",
40 | ResubmitMsg: "请勿重复提交",
41 |
42 | GetError: "查询失败",
43 | CreateError: "添加失败",
44 | UpdateError: "修改失败",
45 | DeleteError: "删除失败",
46 |
47 | LoginErr: "登录失败",
48 | LogoutErr: "注销失败",
49 | }
50 |
51 | func GetErrorMsg(code int) string {
52 | return codeTag[code]
53 | }
54 |
55 | // NewGlobalError 4、新建自定义error实例化
56 | func NewGlobalError(code int, err error) error {
57 | // 初次调用得用Wrap方法,进行实例化
58 | return &GlobalError{
59 | Code: code,
60 | Message: codeTag[code],
61 | RealErrorMessage: err.Error(),
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/pkg/jwt.go:
--------------------------------------------------------------------------------
1 | package pkg
2 |
3 | import (
4 | "errors"
5 | jwt "github.com/dgrijalva/jwt-go"
6 | uuid "github.com/satori/go.uuid"
7 | "time"
8 | )
9 |
10 | var JWTToken jwtToken
11 |
12 | // 定义jwtToken结构体
13 | type jwtToken struct {
14 | secret string
15 | }
16 |
17 | func RegisterJwt(secret string) {
18 | JWTToken.secret = secret
19 | }
20 |
21 | type BaseClaims struct {
22 | UUID uuid.UUID
23 | ID int
24 | Username string
25 | NickName string
26 | AuthorityId uint
27 | }
28 |
29 | // CustomClaims 自定义token中携带的信息
30 | type CustomClaims struct {
31 | BaseClaims
32 | jwt.StandardClaims
33 | }
34 |
35 | // GenerateToken 生成token函数方法
36 | func (j *jwtToken) GenerateToken(baseClaims BaseClaims) (string, error) {
37 | nowTime := time.Now()
38 | expireTime := nowTime.Add(24 * time.Hour)
39 | claims := CustomClaims{
40 | baseClaims,
41 | jwt.StandardClaims{
42 | NotBefore: time.Now().Unix() - 1000, // 签名生效时间
43 | ExpiresAt: expireTime.Unix(),
44 | Issuer: "kubemanage", // 签名的发行者
45 | },
46 | }
47 | tokenClaims := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
48 | token, err := tokenClaims.SignedString([]byte(j.secret))
49 | return token, err
50 | }
51 |
52 | // ParseToken 解析token函数
53 | func (j *jwtToken) ParseToken(tokenString string) (claims *CustomClaims, err error) {
54 | // 使用jwt.ParseWithClaims方法解析token,这个token是前端传给我们的,获得一个*Token类型的对象
55 | token, err := jwt.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwt.Token) (interface{}, error) {
56 | return []byte(j.secret), nil
57 | })
58 | if err != nil {
59 | // 处理token解析后的各种错误
60 | if ve, ok := err.(*jwt.ValidationError); ok {
61 | if ve.Errors == jwt.ValidationErrorExpired {
62 | return nil, errors.New("登录已过期,请重新登录")
63 | } else {
64 | return nil, errors.New("token不可用," + err.Error())
65 | }
66 | }
67 | }
68 | // 转换为*CustomClaims类型并返回
69 | if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
70 | // 如果解析成功并且token是可用的
71 | return claims, nil
72 | }
73 | return nil, errors.New("解析token失败")
74 | }
75 |
--------------------------------------------------------------------------------
/pkg/logger/interface.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "go.uber.org/zap"
5 |
6 | "github.com/noovertime7/kubemanage/pkg/globalError"
7 | )
8 |
9 | type Logger interface {
10 | Info(msg interface{})
11 | Infof(template string, args ...interface{})
12 | Warn(msg interface{})
13 | Warnf(template string, args ...interface{})
14 | Error(msg interface{})
15 | ErrorWithCode(code int, err error)
16 | ErrorWithErr(msg string, err error)
17 | }
18 |
19 | func New() Logger {
20 | return logger{}
21 | }
22 |
23 | type logger struct{}
24 |
25 | func (logger) Info(msg interface{}) {
26 | LG.Sugar().Info(msg)
27 | }
28 |
29 | func (logger) Infof(template string, args ...interface{}) {
30 | LG.Sugar().Infof(template, args)
31 | }
32 | func (logger) Warn(msg interface{}) {
33 | LG.Sugar().Warn(msg)
34 | }
35 |
36 | func (logger) Warnf(template string, args ...interface{}) {
37 | LG.Sugar().Warnf(template, args)
38 | }
39 |
40 | func (logger) ErrorWithCode(code int, err error) {
41 | msg := globalError.GetErrorMsg(code)
42 | LG.Error(msg, zap.Error(err))
43 | }
44 |
45 | func (logger) Error(msg interface{}) {
46 | LG.Sugar().Error(msg)
47 | }
48 |
49 | func (logger) ErrorWithErr(msg string, err error) {
50 | LG.Error(msg, zap.Error(err))
51 | }
52 |
--------------------------------------------------------------------------------
/pkg/logger/zap.go:
--------------------------------------------------------------------------------
1 | package logger
2 |
3 | import (
4 | "os"
5 | "time"
6 |
7 | "github.com/natefinch/lumberjack"
8 | "go.uber.org/zap"
9 | "go.uber.org/zap/zapcore"
10 |
11 | "github.com/noovertime7/kubemanage/cmd/app/config"
12 | )
13 |
14 | var LG *zap.Logger
15 |
16 | // InitLogger 初始化lg
17 | func InitLogger() (err error) {
18 | cfg := config.SysConfig.Log
19 | writeSyncer := getLogWriter(cfg.Filename, cfg.MaxSize, cfg.MaxBackups, cfg.MaxAge)
20 | encoder := getEncoder()
21 | var l = new(zapcore.Level)
22 | err = l.UnmarshalText([]byte(cfg.Level))
23 | if err != nil {
24 | return
25 | }
26 | var core zapcore.Core
27 | if cfg.Level == "debug" {
28 | // 进入开发模式,日志输出到终端
29 | config := zap.NewDevelopmentEncoderConfig()
30 | // 设置日志颜色
31 | config.EncodeLevel = zapcore.LowercaseColorLevelEncoder
32 | // 设置自定义时间格式
33 | config.EncodeTime = getCustomTimeEncoder
34 | consoleEncoder := zapcore.NewConsoleEncoder(config)
35 | core = zapcore.NewTee(
36 | zapcore.NewCore(encoder, writeSyncer, l),
37 | zapcore.NewCore(consoleEncoder, zapcore.Lock(os.Stdout), zapcore.DebugLevel),
38 | )
39 | } else {
40 | core = zapcore.NewCore(encoder, writeSyncer, l)
41 | }
42 |
43 | LG = zap.New(core, zap.AddCaller())
44 |
45 | zap.ReplaceGlobals(LG)
46 | zap.L().Info("init logger success")
47 | return
48 | }
49 |
50 | func getEncoder() zapcore.Encoder {
51 | encoderConfig := zap.NewProductionEncoderConfig()
52 | encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder
53 | encoderConfig.TimeKey = "time"
54 | encoderConfig.EncodeLevel = zapcore.CapitalColorLevelEncoder
55 | encoderConfig.EncodeDuration = zapcore.SecondsDurationEncoder
56 | encoderConfig.EncodeCaller = zapcore.ShortCallerEncoder
57 | return zapcore.NewJSONEncoder(encoderConfig)
58 | }
59 |
60 | func getLogWriter(filename string, maxSize, maxBackup, maxAge int) zapcore.WriteSyncer {
61 | lumberJackLogger := &lumberjack.Logger{
62 | Filename: filename,
63 | MaxSize: maxSize,
64 | MaxBackups: maxBackup,
65 | MaxAge: maxAge,
66 | }
67 | return zapcore.AddSync(lumberJackLogger)
68 | }
69 |
70 | // CustomTimeEncoder 自定义日志输出时间格式
71 | func getCustomTimeEncoder(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
72 | enc.AppendString("[kubemanage] " + t.Format("2006/01/02 - 15:04:05.000"))
73 | }
74 |
--------------------------------------------------------------------------------
/pkg/params.go:
--------------------------------------------------------------------------------
1 | package pkg
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/go-playground/universal-translator"
6 | "github.com/pkg/errors"
7 | "gopkg.in/go-playground/validator.v9"
8 | "strings"
9 | )
10 |
11 | func DefaultGetValidParams(c *gin.Context, params interface{}) error {
12 | if err := c.ShouldBind(params); err != nil {
13 | return err
14 | }
15 | //获取验证器
16 | valid, err := GetValidator(c)
17 | if err != nil {
18 | return err
19 | }
20 | //获取翻译器
21 | trans, err := GetTranslation(c)
22 | if err != nil {
23 | return err
24 | }
25 | err = valid.Struct(params)
26 | if err != nil {
27 | errs := err.(validator.ValidationErrors)
28 | sliceErrs := []string{}
29 | for _, e := range errs {
30 | sliceErrs = append(sliceErrs, e.Translate(trans))
31 | }
32 | return errors.New(strings.Join(sliceErrs, ","))
33 | }
34 | return nil
35 | }
36 |
37 | func GetValidator(c *gin.Context) (*validator.Validate, error) {
38 | val, ok := c.Get(ValidatorKey)
39 | if !ok {
40 | return nil, errors.New("未设置验证器")
41 | }
42 | validatorObj, ok := val.(*validator.Validate)
43 | if !ok {
44 | return nil, errors.New("获取验证器失败")
45 | }
46 |
47 | return validatorObj, nil
48 | }
49 |
50 | func GetTranslation(c *gin.Context) (ut.Translator, error) {
51 | trans, ok := c.Get(TranslatorKey)
52 | if !ok {
53 | return nil, errors.New("未设置翻译器")
54 | }
55 | translator, ok := trans.(ut.Translator)
56 | if !ok {
57 | return nil, errors.New("获取翻译器失败")
58 | }
59 | return translator, nil
60 | }
61 |
--------------------------------------------------------------------------------
/pkg/password.go:
--------------------------------------------------------------------------------
1 | package pkg
2 |
3 | import (
4 | "golang.org/x/crypto/bcrypt"
5 | )
6 |
7 | func GenSaltPassword(password string) (string, error) {
8 | bytes, err := bcrypt.GenerateFromPassword([]byte(password), 14)
9 | return string(bytes), err
10 | }
11 |
12 | func CheckPassword(password, hashPassword string) bool {
13 | err := bcrypt.CompareHashAndPassword([]byte(hashPassword), []byte(password))
14 | return err == nil
15 | }
16 |
--------------------------------------------------------------------------------
/pkg/source/initializer.go:
--------------------------------------------------------------------------------
1 | package source
2 |
3 | import (
4 | "context"
5 | "github.com/pkg/errors"
6 | "gorm.io/gorm"
7 | )
8 |
9 | type SubInitializer interface {
10 | InitializerName() string // 不一定代表单独一个表,所以改成了更宽泛的语义
11 | MigrateTable(ctx context.Context, db *gorm.DB) error
12 | InitializeData(ctx context.Context, db *gorm.DB) error
13 | TableCreated(ctx context.Context, db *gorm.DB) bool
14 | }
15 |
16 | type InitHandler interface {
17 | InitTables(ctx context.Context, inits initSlice) error // 建表 handler
18 | }
19 |
20 | type initSlice []SubInitializer
21 |
22 | var initializers initSlice
23 |
24 | // RegisterInit 注册要执行的初始化过程,会在 InitDB() 时调用
25 | func RegisterInit(i SubInitializer) {
26 | if initializers == nil {
27 | initializers = initSlice{}
28 | }
29 | initializers = append(initializers, i)
30 | }
31 |
32 | type initDBService struct {
33 | db *gorm.DB
34 | }
35 |
36 | func NewInitDBService(db *gorm.DB) *initDBService {
37 | return &initDBService{db: db}
38 | }
39 |
40 | func (i *initDBService) InitDB() error {
41 | if len(initializers) == 0 {
42 | return errors.New("无可用初始化过程,请检查初始化是否已执行完成")
43 | }
44 | // TODO support more database
45 | handler := newMysqlInitHandler(i.db)
46 | return handler.InitTables(context.TODO(), initializers)
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/source/mysqlinitHandler.go:
--------------------------------------------------------------------------------
1 | package source
2 |
3 | import (
4 | "context"
5 | "gorm.io/gorm"
6 | )
7 |
8 | type mysqlInitHandler struct {
9 | db *gorm.DB
10 | }
11 |
12 | var _ InitHandler = &mysqlInitHandler{}
13 |
14 | func newMysqlInitHandler(db *gorm.DB) InitHandler {
15 | return &mysqlInitHandler{db: db}
16 | }
17 |
18 | func (m *mysqlInitHandler) InitTables(ctx context.Context, inits initSlice) error {
19 | if err := m.createTables(ctx, inits); err != nil {
20 | return err
21 | }
22 | if err := m.createDatas(ctx, inits); err != nil {
23 | return err
24 | }
25 | return nil
26 | }
27 |
28 | func (m *mysqlInitHandler) createTables(ctx context.Context, inits initSlice) error {
29 | for _, init := range inits {
30 | if init.TableCreated(ctx, m.db) {
31 | continue
32 | }
33 | if err := init.MigrateTable(ctx, m.db); err != nil {
34 | return err
35 | }
36 | }
37 | return nil
38 | }
39 |
40 | func (m *mysqlInitHandler) createDatas(ctx context.Context, inits initSlice) error {
41 | for _, init := range inits {
42 | if err := init.InitializeData(ctx, m.db); err != nil {
43 | return err
44 | }
45 | }
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/pkg/source/systemInitailzer.go:
--------------------------------------------------------------------------------
1 | package source
2 |
3 | import (
4 | "context"
5 | "github.com/noovertime7/kubemanage/dao/model"
6 | "gorm.io/gorm"
7 | "strings"
8 | )
9 |
10 | func init() {
11 | RegisterInit(&SystemInitTable{})
12 | }
13 |
14 | type SystemInitTable struct {
15 | }
16 |
17 | func (s *SystemInitTable) InitializerName() string {
18 | return strings.ToUpper("SystemInitTable")
19 | }
20 |
21 | func (s *SystemInitTable) MigrateTable(ctx context.Context, db *gorm.DB) error {
22 | for _, initializer := range model.InitializerList {
23 | if err := initializer.MigrateTable(ctx, db); err != nil {
24 | return err
25 | }
26 | }
27 | return nil
28 | }
29 |
30 | func (s *SystemInitTable) InitializeData(ctx context.Context, db *gorm.DB) error {
31 | for _, initializer := range model.InitializerList {
32 | if err := initializer.InitData(ctx, db); err != nil {
33 | return err
34 | }
35 | }
36 | return nil
37 | }
38 |
39 | func (s *SystemInitTable) TableCreated(ctx context.Context, db *gorm.DB) bool {
40 | yes := true
41 | for _, initializer := range model.InitializerList {
42 | yes = yes && db.Migrator().HasTable(initializer.TableName())
43 | }
44 | return yes
45 | }
46 |
--------------------------------------------------------------------------------
/pkg/types/termisnal.go:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright 2021 The Pixiu Authors.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
14 | limitations under the License.
15 | */
16 |
17 | package types
18 |
19 | import (
20 | "encoding/json"
21 | "fmt"
22 | "net/http"
23 | "time"
24 |
25 | "github.com/gorilla/websocket"
26 | "k8s.io/client-go/tools/remotecommand"
27 | )
28 |
29 | // TerminalMessage 定义了终端和容器 shell 交互内容的格式 Operation 是操作类型
30 | // Data 是具体数据内容 Rows和Cols 可以理解为终端的行数和列数,也就是宽、高
31 | type TerminalMessage struct {
32 | Operation string `json:"operation"`
33 | Data string `json:"data"`
34 | Rows uint16 `json:"rows"`
35 | Cols uint16 `json:"cols"`
36 | }
37 |
38 | // TerminalSession 定义 TerminalSession 结构体,实现 PtyHandler 接口 // wsConn 是 websocket 连接 // sizeChan 用来定义终端输入和输出的宽和高 // doneChan 用于标记退出终端
39 | type TerminalSession struct {
40 | wsConn *websocket.Conn
41 | sizeChan chan remotecommand.TerminalSize
42 | doneChan chan struct{}
43 | }
44 |
45 | // NewTerminalSession 该方法用于升级 http 协议至 websocket,并new一个 TerminalSession 类型的对象返回
46 | func NewTerminalSession(w http.ResponseWriter, r *http.Request) (*TerminalSession, error) {
47 | // 初始化 Upgrader 类型的对象,用于http协议升级为 websocket 协议
48 | upgrader := &websocket.Upgrader{
49 | HandshakeTimeout: time.Second * 2,
50 | // 检测请求来源
51 | CheckOrigin: func(r *http.Request) bool {
52 | return true
53 | },
54 | Subprotocols: []string{r.Header.Get("Sec-WebSocket-Protocol")},
55 | }
56 | conn, err := upgrader.Upgrade(w, r, nil)
57 | if err != nil {
58 | return nil, err
59 | }
60 | session := &TerminalSession{
61 | wsConn: conn,
62 | sizeChan: make(chan remotecommand.TerminalSize),
63 | doneChan: make(chan struct{}),
64 | }
65 |
66 | return session, nil
67 | }
68 |
69 | // 用于读取web端的输入,接收web端输入的指令内容
70 | func (t *TerminalSession) Read(p []byte) (int, error) {
71 | _, message, err := t.wsConn.ReadMessage()
72 | if err != nil {
73 | return copy(p, "\u0004"), err
74 | }
75 | // 反序列化
76 | var msg TerminalMessage
77 | if err = json.Unmarshal(message, &msg); err != nil {
78 | return copy(p, "\u0004"), err
79 | }
80 | // 逻辑判断
81 | switch msg.Operation {
82 | // 如果是标准输入
83 | case "stdin":
84 | return copy(p, msg.Data), nil
85 | // 窗口调整大小
86 | case "resize":
87 | t.sizeChan <- remotecommand.TerminalSize{Width: msg.Cols, Height: msg.Rows}
88 | return 0, nil
89 | // ping 无内容交互
90 | case "ping":
91 | return 0, nil
92 | default:
93 | return copy(p, "\u0004"), fmt.Errorf("unknown message type")
94 | }
95 | }
96 |
97 | // 写数据的方法,拿到 api-server 的返回内容,向web端输出
98 | func (t *TerminalSession) Write(p []byte) (int, error) {
99 | msg, err := json.Marshal(TerminalMessage{
100 | Operation: "stdout",
101 | Data: string(p),
102 | })
103 | if err != nil {
104 | return 0, err
105 | }
106 | if err = t.wsConn.WriteMessage(websocket.TextMessage, msg); err != nil {
107 | return 0, err
108 | }
109 | return len(p), nil
110 | }
111 |
112 | // Done 标记关闭doneChan,关闭后触发退出终端
113 | func (t *TerminalSession) Done() {
114 | close(t.doneChan)
115 | }
116 |
117 | // Close 用于关闭websocket连接
118 | func (t *TerminalSession) Close() error {
119 | return t.wsConn.Close()
120 | }
121 |
122 | // Next 获取web端是否resize,以及是否退出终端
123 | func (t *TerminalSession) Next() *remotecommand.TerminalSize {
124 | select {
125 | case size := <-t.sizeChan:
126 | return &size
127 | case <-t.doneChan:
128 | return nil
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/pkg/utils/auth.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 | "github.com/noovertime7/kubemanage/pkg"
6 | "github.com/pkg/errors"
7 | )
8 |
9 | func GetClaims(c *gin.Context) (*pkg.CustomClaims, error) {
10 | token := c.Request.Header.Get("token")
11 | if token == "" {
12 | return nil, errors.New("请求未携带token,无权限访问")
13 | }
14 | // 解析token内容
15 | claims, err := pkg.JWTToken.ParseToken(token)
16 | if err != nil {
17 | return nil, err
18 | }
19 | return claims, err
20 | }
21 |
22 | // GetUserAuthorityId 从Gin的Context中获取从jwt解析出来的用户角色id
23 | func GetUserAuthorityId(c *gin.Context) (uint, error) {
24 | if claims, exists := c.Get("claims"); !exists {
25 | if cl, err := GetClaims(c); err != nil {
26 | return 0, err
27 | } else {
28 | return cl.AuthorityId, nil
29 | }
30 | } else {
31 | waitUse := claims.(*pkg.CustomClaims)
32 | return waitUse.AuthorityId, nil
33 | }
34 | }
35 |
36 | // GetUserInfo 从Gin的Context中获取从jwt解析出来的用户角色id
37 | func GetUserInfo(c *gin.Context) *pkg.CustomClaims {
38 | if claims, exists := c.Get("claims"); !exists {
39 | if cl, err := GetClaims(c); err != nil {
40 | return nil
41 | } else {
42 | return cl
43 | }
44 | } else {
45 | waitUse := claims.(*pkg.CustomClaims)
46 | return waitUse
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/utils/print.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "fmt"
5 |
6 | "github.com/fatih/color"
7 | )
8 |
9 | var (
10 | Blue = color.New(color.FgHiBlue, color.Bold).SprintFunc()
11 | )
12 |
13 | // PrintLogo 服务启动打印信息
14 | func PrintLogo() {
15 | fmt.Println(Blue(`
16 | /$$ /$$ /$$ /$$ /$$
17 | | $$ /$$/ | $$ | $$$ /$$$
18 | | $$ /$$/ /$$ /$$| $$$$$$$ /$$$$$$ | $$$$ /$$$$ /$$$$$$ /$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$
19 | | $$$$$/ | $$ | $$| $$__ $$ /$$__ $$| $$ $$/$$ $$ |____ $$| $$__ $$ |____ $$ /$$__ $$ /$$__ $$
20 | | $$ $$ | $$ | $$| $$ \ $$| $$$$$$$$| $$ $$$| $$ /$$$$$$$| $$ \ $$ /$$$$$$$| $$ \ $$| $$$$$$$$
21 | | $$\ $$ | $$ | $$| $$ | $$| $$_____/| $$\ $ | $$ /$$__ $$| $$ | $$ /$$__ $$| $$ | $$| $$_____/
22 | | $$ \ $$| $$$$$$/| $$$$$$$/| $$$$$$$| $$ \/ | $$| $$$$$$$| $$ | $$| $$$$$$$| $$$$$$$| $$$$$$$
23 | |__/ \__/ \______/ |_______/ \_______/|__/ |__/ \_______/|__/ |__/ \_______/ \____ $$ \_______/
24 | /$$ \ $$
25 | | $$$$$$/
26 | \______/
27 | `))
28 | }
29 |
30 | func Must(err error) {
31 | panic(err)
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/utils/public.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import "strconv"
4 |
5 | // ParseInt64 将字符串转换为 int64
6 | func ParseInt64(s string) (int64, error) {
7 | if len(s) == 0 {
8 | return 0, nil
9 | }
10 | return strconv.ParseInt(s, 10, 64)
11 | }
12 |
13 | // ParseUint 将字符串转换为 uint
14 | func ParseUint(s string) (uint, error) {
15 | v, err := ParseInt(s)
16 | if err != nil {
17 | return 0, err
18 | }
19 | return uint(v), err
20 | }
21 |
22 | // ParseInt 将字符串转换为 int64
23 | func ParseInt(s string) (int, error) {
24 | if len(s) == 0 {
25 | return 0, nil
26 | }
27 | return strconv.Atoi(s)
28 | }
29 |
--------------------------------------------------------------------------------
/pkg/utils/signal.go:
--------------------------------------------------------------------------------
1 | package utils
2 |
3 | import (
4 | "context"
5 | "os"
6 | "os/signal"
7 | )
8 |
9 | var shutdownSignals = []os.Signal{os.Interrupt}
10 | var onlyOneSignalHandler = make(chan struct{})
11 | var shutdownHandler chan os.Signal
12 |
13 | // SetupSignalHandler registered for SIGTERM and SIGINT. A stop channel is returned
14 | // which is closed on one of these signals. If a second signal is caught, the program
15 | // is terminated with exit code 1.
16 | // Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
17 | // be called once.
18 | func SetupSignalHandler() <-chan struct{} {
19 | return SetupSignalContext().Done()
20 | }
21 |
22 | // SetupSignalContext is same as SetupSignalHandler, but a context.Context is returned.
23 | // Only one of SetupSignalContext and SetupSignalHandler should be called, and only can
24 | // be called once.
25 | func SetupSignalContext() context.Context {
26 | close(onlyOneSignalHandler) // panics when called twice
27 |
28 | shutdownHandler = make(chan os.Signal, 2)
29 |
30 | ctx, cancel := context.WithCancel(context.Background())
31 | signal.Notify(shutdownHandler, shutdownSignals...)
32 | go func() {
33 | <-shutdownHandler
34 | cancel()
35 | <-shutdownHandler
36 | os.Exit(1) // second signal. Exit directly.
37 | }()
38 |
39 | return ctx
40 | }
41 |
42 | // RequestShutdown emulates a received event that is considered as shutdown signal (SIGTERM/SIGINT)
43 | // This returns whether a handler was notified
44 | func RequestShutdown() bool {
45 | if shutdownHandler != nil {
46 | select {
47 | case shutdownHandler <- shutdownSignals[0]:
48 | return true
49 | default:
50 | }
51 | }
52 | return false
53 | }
54 |
--------------------------------------------------------------------------------
/router/router.go:
--------------------------------------------------------------------------------
1 | package router
2 |
3 | import (
4 | "github.com/gin-gonic/gin"
5 |
6 | "github.com/noovertime7/kubemanage/cmd/app/options"
7 | "github.com/noovertime7/kubemanage/controller/api"
8 | "github.com/noovertime7/kubemanage/controller/authority"
9 | "github.com/noovertime7/kubemanage/controller/kubeController"
10 | "github.com/noovertime7/kubemanage/controller/menu"
11 | "github.com/noovertime7/kubemanage/controller/operation"
12 | "github.com/noovertime7/kubemanage/controller/other"
13 | "github.com/noovertime7/kubemanage/controller/user"
14 | "github.com/noovertime7/kubemanage/middleware"
15 | )
16 |
17 | func InstallRouters(opt *options.Options) {
18 | apiGroup := opt.GinEngine.Group("/api")
19 | middleware.InstallMiddlewares(apiGroup)
20 | //安装不需要操作记录路由
21 | {
22 | api.NewApiRouter(apiGroup)
23 | operation.NewOperationRouter(apiGroup)
24 | user.NewUserRouter(apiGroup)
25 | }
26 | installOperationRouters(apiGroup)
27 | }
28 |
29 | func installOperationRouters(apiGroup *gin.RouterGroup) {
30 | // 需要操作记录
31 | apiGroup.Use(middleware.OperationRecord())
32 | {
33 | other.NewSwaggarRoute(apiGroup)
34 | kubeController.NewKubeRouter(apiGroup)
35 | menu.NewMenuRouter(apiGroup)
36 | authority.NewCasbinRouter(apiGroup)
37 | }
38 | }
39 |
--------------------------------------------------------------------------------