mirror of
				https://github.com/1Panel-dev/KubePi.git
				synced 2025-10-31 02:26:57 +08:00 
			
		
		
		
	feat(cluster): 增加集群导入
This commit is contained in:
		
							
								
								
									
										101
									
								
								internal/api/v1/cluster/cluster.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										101
									
								
								internal/api/v1/cluster/cluster.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,101 @@ | ||||
| package cluster | ||||
|  | ||||
| import ( | ||||
| 	kContext "context" | ||||
| 	"fmt" | ||||
| 	v1 "github.com/KubeOperator/ekko/internal/model/v1" | ||||
| 	v1Cluster "github.com/KubeOperator/ekko/internal/model/v1/cluster" | ||||
| 	"github.com/KubeOperator/ekko/internal/service/v1/cluster" | ||||
| 	"github.com/KubeOperator/ekko/internal/util/kubernetes" | ||||
| 	"github.com/asdine/storm/v3" | ||||
| 	"github.com/google/uuid" | ||||
| 	"github.com/kataras/iris/v12" | ||||
| 	"github.com/kataras/iris/v12/context" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
|  | ||||
| type Handler struct { | ||||
| 	clusterService cluster.Cluster | ||||
| } | ||||
|  | ||||
| func NewHandler() *Handler { | ||||
| 	return &Handler{ | ||||
| 		clusterService: cluster.NewClusterService(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (h *Handler) Create() iris.Handler { | ||||
| 	return func(ctx *context.Context) { | ||||
| 		var clusterImport Import | ||||
| 		if err := ctx.ReadJSON(&clusterImport); err != nil { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", err.Error()) | ||||
| 			return | ||||
| 		} | ||||
| 		c, err := h.clusterService.Get(clusterImport.Name) | ||||
| 		if err != nil && err != storm.ErrNotFound { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", fmt.Sprintf("error: %s", err.Error())) | ||||
| 			return | ||||
| 		} | ||||
| 		if c != nil && c.Name != "" { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", fmt.Sprintf("cluster name %s is alerady exist", clusterImport.Name)) | ||||
| 			return | ||||
| 		} | ||||
| 		client, err := kubernetes.NewKubernetesClient(&kubernetes.Config{ | ||||
| 			Host:  clusterImport.ApiServer, | ||||
| 			Token: clusterImport.Token, | ||||
| 		}) | ||||
| 		if err != nil { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", fmt.Sprintf("import cluster filed: %s", err.Error())) | ||||
| 			return | ||||
| 		} | ||||
| 		_, err = client.CoreV1().Namespaces().List(kContext.TODO(), metav1.ListOptions{}) | ||||
| 		if err != nil { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", fmt.Sprintf("import cluster failed: %s", err.Error())) | ||||
| 			return | ||||
| 		} | ||||
| 		cs := v1Cluster.Cluster{ | ||||
| 			Metadata: v1.Metadata{ | ||||
| 				Name: clusterImport.Name, | ||||
| 				UUID: uuid.New().String(), | ||||
| 			}, | ||||
| 			Token:     clusterImport.Token, | ||||
| 			Router:    clusterImport.Router, | ||||
| 			ApiServer: clusterImport.ApiServer, | ||||
| 			Status:    "Running", | ||||
| 		} | ||||
| 		err = h.clusterService.Create(&cs) | ||||
| 		if err != nil { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", fmt.Sprintf("create cluster failed: %s", err.Error())) | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.StatusCode(iris.StatusOK) | ||||
| 		ctx.Values().Set("data", cs) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (h *Handler) ListAll() iris.Handler { | ||||
| 	return func(ctx *context.Context) { | ||||
| 		var clusters []v1Cluster.Cluster | ||||
| 		clusters, err := h.clusterService.All() | ||||
| 		if err != nil { | ||||
| 			ctx.StatusCode(iris.StatusBadRequest) | ||||
| 			ctx.Values().Set("message", fmt.Sprintf("get clusters failed: %s", err.Error())) | ||||
| 			return | ||||
| 		} | ||||
| 		ctx.StatusCode(iris.StatusOK) | ||||
| 		ctx.Values().Set("data", clusters) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func Install(parent iris.Party) { | ||||
| 	handler := NewHandler() | ||||
| 	sp := parent.Party("/clusters") | ||||
| 	sp.Post("", handler.Create()) | ||||
| 	sp.Get("", handler.ListAll()) | ||||
| } | ||||
							
								
								
									
										8
									
								
								internal/api/v1/cluster/types.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								internal/api/v1/cluster/types.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| package cluster | ||||
|  | ||||
| type Import struct { | ||||
| 	Name      string `json:"name"` | ||||
| 	ApiServer string `json:"apiServer"` | ||||
| 	Router    string `json:"router"` | ||||
| 	Token     string `json:"token"` | ||||
| } | ||||
| @@ -1,6 +1,7 @@ | ||||
| package v1 | ||||
|  | ||||
| import ( | ||||
| 	"github.com/KubeOperator/ekko/internal/api/v1/cluster" | ||||
| 	"github.com/KubeOperator/ekko/internal/api/v1/session" | ||||
| 	"github.com/kataras/iris/v12" | ||||
| ) | ||||
| @@ -8,4 +9,5 @@ import ( | ||||
| func AddV1Route(app iris.Party) { | ||||
| 	v1Party := app.Party("/v1") | ||||
| 	session.Install(v1Party) | ||||
| 	cluster.Install(v1Party) | ||||
| } | ||||
|   | ||||
							
								
								
									
										12
									
								
								internal/model/v1/cluster/cluster.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										12
									
								
								internal/model/v1/cluster/cluster.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| package cluster | ||||
|  | ||||
| import v1 "github.com/KubeOperator/ekko/internal/model/v1" | ||||
|  | ||||
| type Cluster struct { | ||||
| 	v1.BaseModel `storm:"inline"` | ||||
| 	v1.Metadata  `storm:"inline"` | ||||
| 	ApiServer    string `json:"apiServer"` | ||||
| 	Router       string `json:"router"` | ||||
| 	Token        string `json:"token"` | ||||
| 	Status       string `json:"status"` | ||||
| } | ||||
							
								
								
									
										42
									
								
								internal/service/v1/cluster/cluster.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								internal/service/v1/cluster/cluster.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| package cluster | ||||
|  | ||||
| import ( | ||||
| 	v1Cluster "github.com/KubeOperator/ekko/internal/model/v1/cluster" | ||||
| 	"github.com/KubeOperator/ekko/internal/server" | ||||
| ) | ||||
|  | ||||
| type Cluster interface { | ||||
| 	Create(cluster *v1Cluster.Cluster) error | ||||
| 	Get(name string) (*v1Cluster.Cluster, error) | ||||
| 	All() ([]v1Cluster.Cluster, error) | ||||
| } | ||||
|  | ||||
| func NewClusterService() Cluster { | ||||
| 	return &cluster{} | ||||
| } | ||||
|  | ||||
| type cluster struct { | ||||
| } | ||||
|  | ||||
| func (c *cluster) Create(cluster *v1Cluster.Cluster) error { | ||||
| 	db := server.DB() | ||||
| 	return db.Save(cluster) | ||||
| } | ||||
|  | ||||
| func (c *cluster) Get(name string) (*v1Cluster.Cluster, error) { | ||||
| 	db := server.DB() | ||||
| 	var cluster v1Cluster.Cluster | ||||
| 	if err := db.One("Name", name, &cluster); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &cluster, nil | ||||
| } | ||||
|  | ||||
| func (c *cluster) All() ([]v1Cluster.Cluster, error) { | ||||
| 	db := server.DB() | ||||
| 	var clusters []v1Cluster.Cluster | ||||
| 	if err := db.All(&clusters); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return clusters, nil | ||||
| } | ||||
							
								
								
									
										23
									
								
								internal/util/kubernetes/client.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								internal/util/kubernetes/client.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"k8s.io/client-go/kubernetes" | ||||
| 	"k8s.io/client-go/rest" | ||||
| ) | ||||
|  | ||||
| type Config struct { | ||||
| 	Host  string | ||||
| 	Token string | ||||
| } | ||||
|  | ||||
| func NewKubernetesClient(c *Config) (*kubernetes.Clientset, error) { | ||||
| 	kubeConf := &rest.Config{ | ||||
| 		Host:        c.Host, | ||||
| 		BearerToken: c.Token, | ||||
| 		TLSClientConfig: rest.TLSClientConfig{ | ||||
| 			Insecure: true, | ||||
| 		}, | ||||
| 	} | ||||
| 	return kubernetes.NewForConfig(kubeConf) | ||||
|  | ||||
| } | ||||
							
								
								
									
										23
									
								
								internal/util/kubernetes/client_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								internal/util/kubernetes/client_test.go
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| package kubernetes | ||||
|  | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	"testing" | ||||
| ) | ||||
|  | ||||
| func TestNewKubernetesClient(t *testing.T) { | ||||
| 	c, err := NewKubernetesClient(&Config{ | ||||
| 		Host:  "172.16.10.125:8443", | ||||
| 		Token: "eyJhbGciOiJSUzI1NiIsImtpZCI6Ii1odW5XaTdXY1ZTZmdRWVJFLTN4aUhLemttN21mOV83TG9jbmp5dzJtR1kifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJrdWJlLXN5c3RlbSIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VjcmV0Lm5hbWUiOiJrby1hZG1pbi10b2tlbi05c21kMiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50Lm5hbWUiOiJrby1hZG1pbiIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjhjYTNlZjExLWU3YTMtNGU2Zi1iNzljLTI2NzMzZDY1MmQ5ZiIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDprdWJlLXN5c3RlbTprby1hZG1pbiJ9.ntgCFo_UL8Hah69Nba__RwJbUGEvznUFAWX2XRXII5kexC_av5isAp3rJyv-Lqq_qGd9mJcDGm0TodMo4sP46qsMuKQ-LM6-lvCK77-y5wnGuqyXjT9C6-h7nOfP55gCaOX9mNY40l2fgjVVLcaaTklB9-QceRFgOzfjRZGwcExyL-JNepw78yMnRM_g1fV4w1VduBqniOgoM5uzACJPO-viyoZPmedCadMlnKhJnETshAe_zNZT9yZ90ujwprI9znrJLt6szLmQgK24EbcG4KF3T9PLyIBO_K0clG_U36Q14DowCLRenKZw9HOsU-AbAzwIGMjj2x8QohGDMZglRw", | ||||
| 	}) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
| 	l, err := c.CoreV1().ServiceAccounts("default").List(context.TODO(), metav1.ListOptions{}) | ||||
| 	if err != nil { | ||||
| 		fmt.Println(err) | ||||
| 	} | ||||
| 	fmt.Println(l) | ||||
| } | ||||
							
								
								
									
										11
									
								
								ui/src/api/clusters.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								ui/src/api/clusters.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| import {post,get} from "@/plugins/request" | ||||
|  | ||||
| const authUrl = "/api/v1/clusters" | ||||
|  | ||||
| export function create(data) { | ||||
|   return post(authUrl, data) | ||||
| } | ||||
|  | ||||
| export function listAll(){ | ||||
|   return get(authUrl) | ||||
| } | ||||
| @@ -6,11 +6,25 @@ | ||||
|         <div class="grid-content bg-purple-light"> | ||||
|           <el-form :model="form" label-position="left" :rules="rules" label-width="120px"> | ||||
|             <el-form-item :label="$t('commons.table.name')" prop="name"> | ||||
|                   <el-input style="width: 100%" v-model="form.name" clearable></el-input> | ||||
|               <el-input v-model="form.name" clearable></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="apiServer" prop="apiServer"> | ||||
|               <el-input v-model="form.apiServer" :placeholder="$t('business.cluster.api_server_help')" | ||||
|                         clearable></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="router" prop="router"> | ||||
|               <el-input v-model="form.router" :placeholder="$t('business.cluster.router_help')" clearable></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item label="token" prop="token"> | ||||
|               <el-input type="textarea" :autosize="{ minRows: 2}" style="width: 100%" v-model="form.token" | ||||
|                         clearable></el-input> | ||||
|             </el-form-item> | ||||
|             <el-form-item style="float: right"> | ||||
|               <el-button @click="onCancel()">{{ $t("commons.button.cancel") }}</el-button> | ||||
|                 <el-button v-loading="loading" @click="onSubmit" type="primary">{{ $t("commons.button.create") }}</el-button> | ||||
|               <el-button v-loading="loading" @click="onSubmit" type="primary">{{ | ||||
|                   $t("commons.button.create") | ||||
|                 }} | ||||
|               </el-button> | ||||
|             </el-form-item> | ||||
|           </el-form> | ||||
|         </div> | ||||
| @@ -21,6 +35,7 @@ | ||||
|  | ||||
| <script> | ||||
| import LayoutContent from "@/components/layout/LayoutContent" | ||||
| import {create} from "@/api/clusters" | ||||
|  | ||||
| export default { | ||||
|   name: "ClusterImport", | ||||
| @@ -28,7 +43,10 @@ export default { | ||||
|   data () { | ||||
|     return { | ||||
|       form: { | ||||
|         name: "" | ||||
|         name: "", | ||||
|         apiServer: "", | ||||
|         router: "", | ||||
|         token: "" | ||||
|       }, | ||||
|       rules: {}, | ||||
|       loading: false | ||||
| @@ -40,7 +58,12 @@ export default { | ||||
|  | ||||
|     }, | ||||
|     onSubmit () { | ||||
|  | ||||
|       create(this.form).then(() => { | ||||
|         this.$message({ | ||||
|           type: "success", | ||||
|           message: this.$t("创建成功") | ||||
|         }) | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
| } | ||||
|   | ||||
| @@ -25,6 +25,7 @@ | ||||
| <script> | ||||
| import LayoutContent from "@/components/layout/LayoutContent" | ||||
| import ComplexTable from "@/components/complex-table" | ||||
| import {listAll} from "@/api/clusters" | ||||
|  | ||||
| export default { | ||||
|   name: "ClusterList", | ||||
| @@ -50,8 +51,6 @@ export default { | ||||
|         ], | ||||
|       }, | ||||
|       data: [ | ||||
|         { name: "测试" }, | ||||
|         { name: "测试2" } | ||||
|       ], | ||||
|       selects: [] | ||||
|     } | ||||
| @@ -60,6 +59,14 @@ export default { | ||||
|     onImport () { | ||||
|       this.$router.push({ name: "ClusterImport" }) | ||||
|     }, | ||||
|     list() { | ||||
|       listAll().then(res => { | ||||
|         this.data =res.data | ||||
|       }) | ||||
|     } | ||||
|   }, | ||||
|   created () { | ||||
|     this.list() | ||||
|   } | ||||
| } | ||||
| </script> | ||||
|   | ||||
| @@ -58,7 +58,9 @@ const message = { | ||||
|     cluster: { | ||||
|       cluster: "集群", | ||||
|       list: "集群列表", | ||||
|       import: "导入集群" | ||||
|       import: "导入集群", | ||||
|       api_server_help: "例如: https://172.16.10.100:8443", | ||||
|       router_help: "装有 kube-proxy 的任意节点的且可以被访问到的 IP 地址", | ||||
|     }, | ||||
|     workload: { | ||||
|       workload: "工作量" | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 wangzhengkun
					wangzhengkun