【k8s多集群管理平台开发实践】八、client-go实现service读取列表、创建service、读取yaml配置并更新

文章目录

        • 简介
      • 一.k8s的service列表
        • 1.1.controllers控制器代码
        • 1.2.models模型代码
      • 二.创建service
        • 2.1.controllers控制器代码
        • 2.2.models模分代码
      • 三.读取和更新service的yaml配置
        • 3.1.controllers控制器代码
        • 3.2.models模型代码
      • 四.路由设置
        • 4.1.路由设置
      • 五.前端代码
        • 5.1.列表部分html代码
        • 5.2.创建表单html代码
        • 5.3.显示yaml配置的html代码
      • 六.完整代码
        • 6.1.控制器service.go的完整代码
        • 6.2.模型serviceModel.go的完整代码
      • 七.效果图

简介

本章节主要讲解通过client-go实现service的列表读取和界面创建service,sevice的yaml配置文件读取和修改,并通过layui实现界面操作,其中包含控制器这部分的代码,模型这部分代码,以及前端的html代码。

一.k8s的service列表

1.1.controllers控制器代码

通过传递集群id、命名空间、服务名称并调用模型代码中serviceList函数来读取列表

func (this *SvcController) List() {clusterId := this.GetString("clusterId")    //集群名称nameSpace := this.GetString("nameSpace")    //命名空间serviceName := this.GetString("serviceName")    //服务名称labels := this.GetString("labels")  //标签:labels=key:valuelabelsKV := strings.Split(labels, ":")var labelsKey, labelsValue stringif len(labelsKV) == 2 {labelsKey = labelsKV[0]labelsValue = labelsKV[1]}//根据传递的参数进行过滤返回服务列表svcList, err := m.SvcList(clusterId, nameSpace, serviceName, labelsKey, labelsValue)msg := "success"code := 0count := len(svcList)if err != nil {log.Println(err)msg = err.Error()code = -1}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg, "count": count, "data": &svcList}this.ServeJSON()
}
1.2.models模型代码

先定义一个结构体Service,通过传递过来的参数,在svcList.Items中循环读取service的信息,然后赋值结构体Service,并追加到定义一个结构体数组var bbb = make([]Service, 0)

type Service struct {ServiceName string `json:"serviceName"` //服务名称NameSpace   string `json:"nameSpace"`   //命名空间Labels      string `json:"labels"`  //标签SvcType     string `json:"svcType"` //service的类型SvcIp       string `json:"svcIp"`   //服务IPSvcPort     string `json:"svcPort"`LanEndpoint string `json:"lanEndpoint"` //内部端点WanEndpoint string `json:"wanEndpoint"` //外部端点CreateTime  string `json:"createTime"`
}type ServicePort struct {PortName   string `json:"portName"`SvcPort    int32  `json:"svcPort"`TargetPort int32  `json:"targetPort"`
}func SvcList(kubeconfig, namespace, serviceName string, labelsKey, labelsValue string) ([]Service, error) {//获取链接clientset := common.ClientSet(kubeconfig)if namespace == "" {    //判断namespace是否为空,空则读取全部命名空间namespace = corev1.NamespaceAll}//定义标签过滤条件var listOptions = metav1.ListOptions{}if labelsKey != "" && labelsValue != "" {listOptions = metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", labelsKey, labelsValue)}}//读取service信息svcList, err := clientset.CoreV1().Services(namespace).List(context.TODO(), listOptions)if err != nil {log.Printf("list service error:%v\n", err)}//fmt.Println("svc count:", len(svcList.Items))//循环items并追加到结构体数组bbb上var bbb = make([]Service, 0)for _, svc := range svcList.Items {//搜索if serviceName != "" {if !strings.Contains(svc.Name, serviceName) {continue}}//提取标签var labelsStr stringfor kk, vv := range svc.ObjectMeta.Labels {labelsStr += fmt.Sprintf("%s:%s,", kk, vv)}if len(labelsStr) > 0 {labelsStr = labelsStr[0 : len(labelsStr)-1]}//提取所有映射的端口var wanEndPoint stringsvcType := fmt.Sprintf("%s", svc.Spec.Type)if svcType == "LoadBalancer" {wanEndPoint = fmt.Sprintf("%s:%d", svc.Status.LoadBalancer.Ingress[0].IP, svc.Spec.Ports[0].Port)}lanEndPoint := ""var svcPort stringif len(svc.Spec.Ports) > 0 {vsapp := svc.Spec.Selector["app"]if vsapp == "" {vsapp = svc.Spec.Selector["k8s-app"]}for _, vv := range svc.Spec.Ports {//lanEndPoint += fmt.Sprintf("%s:%s:%s\n", svc.Spec.Selector["app"], svc.Spec.Ports[0].TargetPort.StrVal, svc.Spec.Ports[0].Protocol)//svcPort += fmt.Sprintf("%s:", svc.Spec.Ports[0].Port)var vport stringif vv.TargetPort.Type == 0 {vport = fmt.Sprintf("%d", vv.TargetPort.IntVal)} else {vport = fmt.Sprintf("%s", vv.TargetPort.StrVal)}lanEndPoint += fmt.Sprintf("%s:%s:%s,", vsapp, vport, vv.Protocol)svcPort += fmt.Sprintf("%d,", vv.Port)}if len(svcPort) > 0 {svcPort = svcPort[0 : len(svcPort)-1]}lanEndPoint = lanEndPoint[0 : len(lanEndPoint)-1]}//赋值到结构体Items := &Service{ServiceName: svc.Name,NameSpace:   svc.Namespace,SvcType:     svcType,SvcIp:       svc.Spec.ClusterIP,Labels:      labelsStr,SvcPort:     svcPort,LanEndpoint: lanEndPoint,WanEndpoint: wanEndPoint,CreateTime:  svc.CreationTimestamp.Format("2006-01-02 15:04:05"),}//追加到数组bbbbbb = append(bbb, *Items)}return bbb, err
}

二.创建service

2.1.controllers控制器代码

将前端的form 表单提交的json数据传递到模型函数serviceCreate来进行解析

func (this *SvcController) Create() {clusterId := this.GetString("clusterId") //集群IDcode := 0msg := "success"//log.Println(string(this.Ctx.Input.RequestBody))//将传递过来的json 二进制 body直接传递到模型中的函数SvcCreate处理err := m.SvcCreate(clusterId, this.Ctx.Input.RequestBody)if err != nil {code = -1msg = err.Error()log.Printf("[ERROR] configmap Create Fail:%s\n", err)}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg}this.ServeJSON()
}
2.2.models模分代码

将控制器Create函数中传递过来的body数据进行json解析,创建一个service实例结构体svcInstance := &corev1.Service,并将解析json出来的数据赋值到结构体中,再调用clientset.CoreV1().Services(nameSpace).Create来进行创建.

func SvcCreate(kubeconfig string, bodys []byte) error {//解析json并提取数据gp := gjson.ParseBytes(bodys)clusterId := gp.Get("clusterId").String()if kubeconfig == "" {kubeconfig = clusterId}serviceName := gp.Get("serviceName").String()   //服务名称nameSpace := gp.Get("nameSpace").String()   //命名空间svcType := gp.Get("svcType").String()   //服务类型deployName := gp.Get("deployName").String() //关联的负载名称isHeadless := gp.Get("isHeadless").Str  //是否是无头服务var labelsMap = make(map[string]string) //提取标签labelsMap["app"] = serviceNamefor _, vv := range gp.Get("lables").Array() {labelsMap[vv.Get("key").Str] = vv.Get("value").Str}selectApp := serviceName    //默认将service的名称和deployment的名称一致,deployName不为空时,按照deployName的名称创建if deployName != "" {selectApp = deployName}var serviceType corev1.ServiceType  //赋值服务类型switch svcType {case "NodePort":serviceType = corev1.ServiceTypeNodePortcase "LoadBalancer":serviceType = corev1.ServiceTypeLoadBalancerdefault:serviceType = corev1.ServiceTypeClusterIP}if isHeadless == "on" { //判断是否是无头服务serviceType = corev1.ServiceTypeClusterIP}//将json解析的数据赋值到service实例结构体上svcInstance := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name:      serviceName,Namespace: nameSpace,Labels:    labelsMap,},Spec: corev1.ServiceSpec{Selector: map[string]string{"app": selectApp,},Type: serviceType,},}if isHeadless == "on" {svcInstance.Spec.ClusterIP = corev1.ClusterIPNone}ports := gp.Get("ports").Array()var svcPorts = make([]corev1.ServicePort, 0)for _, vv := range ports {var svcProtocol corev1.Protocolif vv.Get("protocol").Str == "UDP" {svcProtocol = corev1.ProtocolUDP} else {svcProtocol = corev1.ProtocolTCP}svcPort := &corev1.ServicePort{Name:       vv.Get("portName").Str,Port:       int32(vv.Get("svcPort").Int()),Protocol:   svcProtocol,TargetPort: intstr.FromInt32(int32(vv.Get("targetPort").Int())),}svcPorts = append(svcPorts, *svcPort)}svcInstance.Spec.Ports = svcPorts//根据传递的集群ID进行创建serviceclientset := common.ClientSet(kubeconfig)_, err := clientset.CoreV1().Services(nameSpace).Create(context.TODO(), svcInstance, metav1.CreateOptions{})if err != nil {return err}return nil
}

三.读取和更新service的yaml配置

3.1.controllers控制器代码

通过传递集群id、命名空间、服务名称来进行读取service,并调用模型代码中GetSvcYaml函数来读取yaml配置

//读取yaml配置
func (this *SvcController) Yaml() {clusterId := this.GetString("clusterId")nameSpace := this.GetString("nameSpace")serviceName := this.GetString("serviceName")yamlStr, _ := m.GetSvcYaml(clusterId, nameSpace, serviceName)this.Ctx.WriteString(yamlStr)
}
//更新yaml配置
func (this *SvcController) ModifyByYaml() {clusterId := this.GetString("clusterId")//nameSpace := gp.Get("nameSpace").String()//log.Println(string(this.Ctx.Input.RequestBody))//提取body并替换掉%,否则解析出错bodyByte := []byte(strings.ReplaceAll(string(this.Ctx.Input.RequestBody), "%25", "%"))err := m.SvcYamlModify(clusterId, bodyByte)if err != nil {log.Println(err)}this.Data["json"] = &map[string]interface{}{"code": 0, "msg": "ok"}this.ServeJSON()
}
3.2.models模型代码

先读取service实例信息,然后将实例信息解析成解构,然后解构的字节数据进行yaml序列化处理,并转成字符串进行返回

//读取yaml配置
func GetSvcYaml(kubeconfig, namespace, serviceName string) (string, error) {//先通过传递的信息读取service实例servicesClient := common.ClientSet(kubeconfig).CoreV1().Services(namespace)service, err := servicesClient.Get(context.TODO(), serviceName, metav1.GetOptions{})//将读取的service进行解构serviceUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(service)if err != nil {return "", err}//将结构的service数据进行序列号成yaml的bytesyamlBytes, err := yaml.Marshal(serviceUnstructured)if err != nil {return "", err}//以字符串的形式返回return string(yamlBytes), nil
}//更新yaml配置
func SvcYamlModify(kubeconfig string, yamlData []byte) error {//转成json格式data, err := yamlutil.ToJSON(yamlData)if err != nil {return err}//反序列化到service结构体实例service := &corev1.Service{}err = json.Unmarshal(data, service)if err != nil {return err}//提取出名称和命名空间namespace := service.ObjectMeta.NamespaceserviceName := service.ObjectMeta.Name//调用更新api进行更新clientset := common.ClientSet(kubeconfig)_, err = clientset.CoreV1().Services(namespace).Update(context.TODO(), service, metav1.UpdateOptions{})if err != nil {return err}fmt.Println(namespace, serviceName)return err
}

四.路由设置

4.1.路由设置

将以下代码放到routers/route.go中

beego.Router("/svc/v1/List", &controllers.SvcController{}, "*:List")    //读取service列表beego.Router("/svc/v1/Create", &controllers.SvcController{}, "*:Create") //创建servicebeego.Router("/svc/v1/ModifyByYaml", &controllers.SvcController{}, "*:ModifyByYaml") //更新yaml配置beego.Router("/svc/v1/Yaml", &controllers.SvcController{}, "*:Yaml") //读取yaml配置

五.前端代码

5.1.列表部分html代码

5.1 serviceList.html,放到views/front/page/xkube下

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>service列表</title><meta name="renderer" content="webkit"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><link rel="stylesheet" href="/lib/layui-v2.6.3/css/layui.css" media="all"><link rel="stylesheet" href="/css/public.css" media="all"><script type="text/javascript" src="/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script><script src="/lib/layui-v2.6.3/layui.js" charset="utf-8"></script><script src="/js/xkube.js?v=1" charset="utf-8"></script><script src="/js/lay-config.js?v=1.0.4" charset="utf-8"></script><style type="text/css">.layui-table-cell {height: auto;line-height: 22px !important;text-overflow: inherit;overflow:ellipsis;white-space: normal;}.layui-table-cell .layui-table-tool-panel li {word-break: break-word;}
</style>
</head>
<body>
<div class="layuimini-container"><div class="layuimini-main"><script type="text/html" id="toolbarDemo"><div class="layui-btn-container"><button class="layui-btn layui-btn-normal layui-btn-sm data-add-btn" lay-event="create"><i class="layui-icon">&#xe61f;</i>创建service</button></div></script><table class="layui-table" id="currentTableId" lay-filter="currentTableFilter"></table><script type="text/html" id="currentTableBar"><a class="layui-btn layui-btn-normal layui-btn-sm" lay-event="viewYaml">yaml编辑</a></script></div>
</div></body>
<script type="text/html" id="TagTpl">{{# if (d.labels != "") { }}{{# layui.each(d.labels.split(','), function(index, item){ }}{{# if(index == 0) { }}<span>{{ item }}</span>{{# }else{ }}<br><span>{{ item }}</span>{{# } }}  {{# });  }}{{# }else{  }}<span></span>{{# } }}
</script>	
<script type="text/html" id="ipPortTpl"><span>{{ d.svcIp }}:{{ d.svcPort }}</span>
</script>	
<script>
var clusterId = getQueryString("clusterId");
if (clusterId == null) {clusterId = getCookie("clusterId")
}layui.use(['form', 'table','miniTab'], function () {var $ = layui.jquery,form = layui.form,table = layui.table;miniTab = layui.miniTab,miniTab.listen();table.render({elem: '#currentTableId',url: '/svc/v1/List?clusterId='+clusterId,toolbar: '#toolbarDemo',defaultToolbar: ['filter', 'exports', 'print', {title: '提示',layEvent: 'LAYTABLE_TIPS',icon: 'layui-icon-tips'}],parseData: function(res) { //实现加载全部数据后再分页if(this.page.curr) {result=res.data.slice(this.limit*(this.page.curr-1),this.limit*this.page.curr);}else{result=res.data.slice(0,this.limit);}return {"code": res.code,"msg":'',"count":res.count,"data":result};},cols: [[//{type: "checkbox", width: 50},{field: 'serviceName',title: '名称', sort: true},{field: 'nameSpace',title: '命名空间', sort: true},{field: 'svcType', title: '类型', sort: true},{field: 'svcIp', title: 'IP', sort: true,hide:true},{field: 'svcPort', title: '端口', sort: true,hide:true},{field: '', width:150,title: 'ip端口', sort: true,templet: '#ipPortTpl'},{field: 'lanEndpoint',title: '内部端点', sort: true},{field: 'wanEndpoint', title: '外部端点', sort: true,hide:true},{field: 'labels', title: '标签', sort: true,templet: '#TagTpl'},{field: 'createTime', title: '创建时间'},{title: '操作', minWidth: 250, toolbar: '#currentTableBar', align: "center"}]],//size:'lg',limits: [25, 50, 100],limit: 25,page: true});/*** toolbar监听事件*/table.on('toolbar(currentTableFilter)', function (obj) {if (obj.event === 'create') {  // 监听添加操作var index = layer.open({title: '创建',type: 2,shade: 0.2,maxmin:true,shadeClose: true,area: ['60%', '90%'],content: '/page/xkube/serviceCreate.html?v=1',//end: function(){//	window.parent.location.reload();//关闭open打开的页面时,刷新父页面//}});$(window).on("resize", function () {layer.full(index);});} });table.on('tool(currentTableFilter)', function (obj) {var data = obj.data;if (obj.event === 'viewYaml') {var index = layer.open({title: 'yaml',type: 2,shade: 0.2,maxmin:true,shadeClose: true,area: ['45%', '92%'],content: '/page/xkube/serviceYaml.html?clusterId='+clusterId+'&nameSpace='+data.nameSpace+'&serviceName='+data.serviceName,});$(window).on("resize", function () {layer.full(index);});return false;}});});
</script></body>
</html>
5.2.创建表单html代码

5.2 serviceCreate.html,放到views/front/page/xkube下

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>创建</title><meta name="renderer" content="webkit"><meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"><meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"><link rel="stylesheet" href="/lib/layui-v2.6.3/css/layui.css" media="all"><link rel="stylesheet" href="/css/public.css" media="all"><script type="text/javascript" src="/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script><script src="/lib/layui-v2.6.3/layui.js" charset="utf-8"></script><script src="/js/xkube.js?v=1" charset="utf-8"></script><style>body {background-color: #ffffff;}</style>
</head>
<body>
<div class="layuimini-container"><div class="layuimini-main"><form class="layui-form layui-form-pane" action=""><div class="layui-form-item"><div class="layui-inline"><label class="layui-form-label">当前集群</label><div class="layui-input-inline"><select name="clusterId" lay-filter="cluster_Id" lay-search="" id="cluster_Id"><option value="">请选择集群</option></select></div><label class="layui-form-label">命名空间</label><div class="layui-input-inline"><select name="nameSpace" lay-filter="name_Space" lay-search="" id="name_Space"></select></div></div></div><div class="layui-form-item"><label class="layui-form-label required">svc名称</label><div class="layui-input-inline"><input type="text" name="serviceName" placeholder="不能为空" value="" class="layui-input"></div><label class="layui-form-label">关联</label><div class="layui-input-inline"><input type="text" name="deployName" placeholder="关联的deploy或sts" value="" class="layui-input"></div></div><div class="layui-form-item"><label class="layui-form-label">svc类型</label><div class="layui-input-inline"><select name="svcType" lay-filter="svcType" lay-search="" id="svcType"><option value="ClusterIp" selected="">ClusterIp</option><option value="NodePort">NodePort</option><option value="LoadBalancer">LoadBalancer</option></select></div><div id="isHeadlessTpl"><div class="layui-input-inline"><input type="checkbox" name="isHeadless" lay-skin="primary" lay-filter="isHeadless" title="实例间服务发现(Headless Service)">   </div>             </div></div><div class="serviceTpl"><div class="layui-form-item"><label class="layui-form-label">svc端口</label><div class="layui-input-inline" style="width:120px">  <input type="text" id="svc_portsName0" name="svc_portsName[]" placeholder="名称" value="" class="layui-input"></div><div class="layui-input-inline" style="width:120px">  <input type="text" id="svc_port0" name="svc_port[]" placeholder="服务端口" value="" class="layui-input"></div><div class="layui-input-inline" style="width:120px">  <input type="text" id="svc_targetPort0" name="svc_targetPort[]" placeholder="容器端口" value="" class="layui-input"></div><div class="layui-input-inline" style="width:70px">  <select id="svc_protocol0" name="svc_protocol[]"><option value="TCP" selected="">TCP</option><option value="UDP">UDP</option></select></div><div class="layui-input-inline" style="width:80px">  <button class="layui-btn layui-btn-normal" id="svcaddbtn"><i class="layui-icon layui-icon-add-circle"></i></button></div>                </div> </div><fieldset class="layui-elem-field layui-field-title" style="margin-top: 30px;"><legend>标签与注解</legend></fieldset><div class="labelsTpl"><div class="layui-form-item"><label class="layui-form-label">标签</label><div class="layui-input-inline" style="width:150px">  <input type="text" id="labels_key0" name="labels_key[]" placeholder="key" value="" class="layui-input"></div><div class="layui-input-inline" style="width:150px">  <input type="text" id="labels_value0" name="labels_value[]" placeholder="value" value="" class="layui-input"></div><div class="layui-input-inline" style="width:80px">  <button class="layui-btn layui-btn-normal" id="newaddbtn"><i class="layui-icon layui-icon-add-circle"></i></button></div>                </div> </div><!--<div class="annotationTpl"><div class="layui-form-item"><label class="layui-form-label">注解</label><div class="layui-input-inline" style="width:240px">  <input type="text" id="labels_key0" name="labels_key[]" placeholder="key" value="" class="layui-input"></div><div class="layui-input-inline" style="width:240px">  <input type="text" id="labels_value0" name="labels_value[]" placeholder="value" value="" class="layui-input"></div><div class="layui-input-inline">  <button class="layui-btn layui-btn-normal" id="annotateaddbtn"><i class="layui-icon layui-icon-add-circle"></i></button></div>                </div> </div>--><br><div class="layui-form-item"><div class="layui-input-block"><button class="layui-btn layui-btn-normal" lay-submit lay-filter="saveBtn">确认保存</button></div></div></form></div>
</div>
</body>
<script>//标签删除var TplIndex = 0;function delTpl(id) {TplIndex--;$("#tpl-"+id).remove();}//服务删除var sTplIndex = 0;function delsTpl(id) {sTplIndex--;$("#stpl-"+id).remove();}layui.use(['form'], function () {var form = layui.form,layer = layui.layer,$ = layui.$;$("#isHeadlessTpl").show();form.on('select(svcType)', function (data) { if (data.value == "ClusterIp") {$("#isHeadlessTpl").show();}else{$("#isHeadlessTpl").hide();}});//labes add$('#newaddbtn').on("click",function(){TplIndex++;var addTpl ='<div class="layui-form-item" id="tpl-'+TplIndex+'">' +'<label class="layui-form-label">标签</label>' +'<div class="layui-input-inline" style="width:150px">' +'<input type="text" name="labels_key[]" id="labels_key'+TplIndex+'" placeholder="key" value="" class="layui-input">' +'</div>' +    '<div class="layui-input-inline" style="width:150px">' +  '<input type="text" name="labels_value[]" id="labels_value'+TplIndex+'" placeholder="value" value="" class="layui-input">' +'</div>' +'<div class="layui-input-inline" style="width:80px">' +  '<input class="layui-btn layui-btn-normal layui-bg-orange layui-icon" style="width:60px" type="button" id="newDelbtn" value="&#xe616;" οnclick="delTpl('+TplIndex+');" />' +'</div>' +                '</div>'$('.labelsTpl').append(addTpl);   form.render(); return false;   });//service增加$('#svcaddbtn').on("click",function(){sTplIndex++;var addTpl ='<div class="layui-form-item" id="stpl-'+sTplIndex+'">' +'<label class="layui-form-label">svc端口</label>' +'<div class="layui-input-inline" style="width:120px">' +'<input type="text" name="svc_portsName[]" id="svc_portsName'+sTplIndex+'" placeholder="名称" value="" class="layui-input">' +'</div>' +    '<div class="layui-input-inline" style="width:120px">' +  '<input type="text" name="svc_port[]" id="svc_port'+sTplIndex+'" placeholder="服务端口" value="" class="layui-input">' +'</div>' +'<div class="layui-input-inline" style="width:120px">' +  '<input type="text" name="svc_targetPort[]" id="svc_targetPort'+sTplIndex+'" placeholder="容器端口" value="" class="layui-input">' +'</div>' +'<div class="layui-input-inline" style="width:70px">' +  '<select name="svc_protocol[]" id="svc_protocol'+sTplIndex+'" >' +'<option value="TCP" selected="">TCP</option>' +'<option value="UDP">UDP</option>' +'</select>' +'</div>' +'<div class="layui-input-inline" style="width:80px">' +  '<input class="layui-btn layui-btn-normal layui-bg-orange layui-icon" style="width:60px" type="button" value="&#xe616;" οnclick="delsTpl('+sTplIndex+');" />' +'</div>' +                '</div>'$('.serviceTpl').append(addTpl);   form.render(); return false;   });//监听提交form.on('submit(saveBtn)', function (data) {data.field.serviceName = data.field.serviceName.replace(/^\s*|\s*$/g,""); //替换空格if (data.field.svcType != "ClusterIp") {delete data.field.isHeadless;}         //lables 处理var labelsArry = [];for (var i=0;i<=TplIndex;i++) {//delete data.field.lables_key[i];                  //delete data.field.labels_value[i];var kk = document.getElementById("labels_key"+i).value;var vv = document.getElementById("labels_value"+i).value; if ( kk != "" && vv != "") {labelsArry.push({key:kk,value:vv,})}}if (labelsArry.length > 0) {data.field.lables = labelsArry;}//service 处理var svcArry = [];for (var i=0;i<=sTplIndex;i++) {var kk = document.getElementById("svc_portsName"+i).value;var vv = document.getElementById("svc_port"+i).value; var ss = document.getElementById("svc_targetPort"+i).value; var tt = document.getElementById("svc_protocol"+i).value;if ( kk != "" && vv != "" && ss != "") {svcArry.push({portName:kk,svcPort:vv,targetPort:ss,protocol:tt,})}}if (svcArry.length > 0) {data.field.ports = svcArry;}console.log(data.field);layer.confirm('确定添加?', {icon: 3, title:'提示',yes: function(index){var index2 = layer.load(0, {shade: false});layer.msg('稍等片刻');$.ajax({url: "/svc/v1/Create",type: "post",data: JSON.stringify(data.field),dataType: "json",success: function (resp) {layer.close(index2);if(resp.code == 0){layer.msg('添加成功', {icon: 1});//window.location.reload();}else{layer.msg(resp.msg,{icon:2});}}});		  	  },cancel: function(index, layero){ layer.close(index);layer.close(index2);console.log("不操作");} });return false;});});
</script>
</body>
</html>
5.3.显示yaml配置的html代码

5.3 serviceYaml.html,放到views/front/page/xkube下

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>yaml编辑</title><meta name="renderer" content="webkit"><link rel="stylesheet" href="/lib/layui-v2.6.3/css/layui.css" media="all"><link rel="stylesheet" href="/css/public.css" media="all"><meta http-equiv="Content-Type" content="text/html;charset=utf-8"><linkrel="stylesheet"data-name="vs/editor/editor.main"href="/monaco-editor/min/vs/editor/editor.main.css"/><script src="/js/xkube.js?v=1" charset="utf-8"></script><script type="text/javascript" src="/lib/jquery-3.4.1/jquery-3.4.1.min.js"></script>
</head>
<body>
<div class="layuimini-container"><div class="layuimini-main"><div id="container" style="width: 100%; height:460px; border: 1px solid grey"></div><br><fieldset class="table-search-fieldset"><legend></legend><button class="layui-btn layui-btn-sm" id="SaveBtn" >保存更新</button><button class="layui-btn layui-btn-normal layui-btn-sm" id="DownLoadBtn">下载</button></fieldset>   </div>
</div>
<script src="/lib/layui-v2.6.3/layui.js" charset="utf-8"></script>
<script>var require = { paths: { vs: '/monaco-editor/min/vs' } };
</script>
<script src="/monaco-editor/min/vs/loader.js"></script>
<script src="/monaco-editor/min/vs/editor/editor.main.nls.js"></script>
<script src="/monaco-editor/min/vs/editor/editor.main.js"></script>
<script>layui.use(['form', 'table','code'], function () {var $ = layui.jquery;var form = layui.form,layer = layui.layer;var editor = monaco.editor.create(document.getElementById('container'), {value: '',language: 'yaml',//automaticLayout: true,minimap: {enabled: false},wordWrap: 'on',theme: 'vs-dark'});$.ajax({url: "/svc/v1/Yaml"+location.search,type: "GET",success: function (resp) {//codeyaml = resp;editor.setValue(resp);}});	$('#SaveBtn').on("click",function(){var yamlBody = editor.getValue();yamlBody = yamlBody.replace(/%/g,"%25");layer.confirm('确定修改?', {icon: 3, title:'提示',yes: function(index){$.ajax({url: "/svc/v1/ModifyByYaml"+location.search,type: "POST",data: yamlBody,dataType: "json",success: function (resp) {layer.msg(resp.msg);console.log(resp);}});//console.log(editor.getValue());//layer.msg('ok');},cancel: function(index, layero){ layer.close(index);} });});$('#DownLoadBtn').on("click",function(){var serviceName = getQueryString("serviceName");ExportRaw(serviceName+'.yaml',editor.getValue());});});
</script></body>
</html>

六.完整代码

6.1.控制器service.go的完整代码

6.1 service.go,放到contrillers下

// service.go
package controllersimport (//"encoding/json"//"fmt""log"m "myk8s/models""strings"beego "github.com/beego/beego/v2/server/web"
)type SvcController struct {beego.Controller
}func (this *SvcController) List() {clusterId := this.GetString("clusterId")nameSpace := this.GetString("nameSpace")serviceName := this.GetString("serviceName")labels := this.GetString("labels")labelsKV := strings.Split(labels, ":")var labelsKey, labelsValue stringif len(labelsKV) == 2 {labelsKey = labelsKV[0]labelsValue = labelsKV[1]}svcList, err := m.SvcList(clusterId, nameSpace, serviceName, labelsKey, labelsValue)msg := "success"code := 0count := len(svcList)if err != nil {log.Println(err)msg = err.Error()code = -1}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg, "count": count, "data": &svcList}this.ServeJSON()
}func (this *SvcController) Create() {clusterId := this.GetString("clusterId")code := 0msg := "success"//log.Println(string(this.Ctx.Input.RequestBody))err := m.SvcCreate(clusterId, this.Ctx.Input.RequestBody)if err != nil {code = -1msg = err.Error()log.Printf("[ERROR] configmap Create Fail:%s\n", err)}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg}this.ServeJSON()
}func (this *SvcController) ModifyByYaml() {clusterId := this.GetString("clusterId")//nameSpace := gp.Get("nameSpace").String()log.Println(string(this.Ctx.Input.RequestBody))bodyByte := []byte(strings.ReplaceAll(string(this.Ctx.Input.RequestBody), "%25", "%"))err := m.SvcYamlModify(clusterId, bodyByte)if err != nil {log.Println(err)}this.Data["json"] = &map[string]interface{}{"code": 0, "msg": "ok"}this.ServeJSON()
}func (this *SvcController) Yaml() {clusterId := this.GetString("clusterId")nameSpace := this.GetString("nameSpace")serviceName := this.GetString("serviceName")yamlStr, _ := m.GetSvcYaml(clusterId, nameSpace, serviceName)this.Ctx.WriteString(yamlStr)
}
6.2.模型serviceModel.go的完整代码

6.2 serviceModel.go,放到models下

// serviceModel.go
package modelsimport ("context""fmt""log""myk8s/common""strings""encoding/json""github.com/tidwall/gjson"//"k8s.io/apimachinery/pkg/api/errors"corev1 "k8s.io/api/core/v1"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"yamlutil "k8s.io/apimachinery/pkg/util/yaml""k8s.io/apimachinery/pkg/runtime""k8s.io/apimachinery/pkg/util/intstr""sigs.k8s.io/yaml"
)type Service struct {ServiceName string `json:"serviceName"` //服务名称NameSpace   string `json:"nameSpace"`Labels      string `json:"labels"`SvcType     string `json:"svcType"`SvcIp       string `json:"svcIp"`SvcPort     string `json:"svcPort"`LanEndpoint string `json:"lanEndpoint"` //内部端点WanEndpoint string `json:"wanEndpoint"` //外部端点CreateTime  string `json:"createTime"`
}type ServicePort struct {PortName   string `json:"portName"`SvcPort    int32  `json:"svcPort"`TargetPort int32  `json:"targetPort"`
}func SvcList(kubeconfig, namespace, serviceName string, labelsKey, labelsValue string) ([]Service, error) {clientset := common.ClientSet(kubeconfig)if namespace == "" {//namespace = corev1.NamespaceDefaultnamespace = corev1.NamespaceAll}//var selector labels.Selectorvar listOptions = metav1.ListOptions{}if labelsKey != "" && labelsValue != "" {listOptions = metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", labelsKey, labelsValue)}}svcList, err := clientset.CoreV1().Services(namespace).List(context.TODO(), listOptions)if err != nil {log.Printf("list service error:%v\n", err)}//fmt.Println("svc count:", len(svcList.Items))var bbb = make([]Service, 0)for _, svc := range svcList.Items {//搜索if serviceName != "" {if !strings.Contains(svc.Name, serviceName) {continue}}//fmt.Printf("name: %s\n", svc.Name)var labelsStr stringfor kk, vv := range svc.ObjectMeta.Labels {labelsStr += fmt.Sprintf("%s:%s,", kk, vv)}if len(labelsStr) > 0 {labelsStr = labelsStr[0 : len(labelsStr)-1]}var wanEndPoint stringsvcType := fmt.Sprintf("%s", svc.Spec.Type)if svcType == "LoadBalancer" {wanEndPoint = fmt.Sprintf("%s:%d", svc.Status.LoadBalancer.Ingress[0].IP, svc.Spec.Ports[0].Port)}lanEndPoint := ""var svcPort stringif len(svc.Spec.Ports) > 0 {vsapp := svc.Spec.Selector["app"]if vsapp == "" {vsapp = svc.Spec.Selector["k8s-app"]}for _, vv := range svc.Spec.Ports {//lanEndPoint += fmt.Sprintf("%s:%s:%s\n", svc.Spec.Selector["app"], svc.Spec.Ports[0].TargetPort.StrVal, svc.Spec.Ports[0].Protocol)//svcPort += fmt.Sprintf("%s:", svc.Spec.Ports[0].Port)var vport stringif vv.TargetPort.Type == 0 {vport = fmt.Sprintf("%d", vv.TargetPort.IntVal)} else {vport = fmt.Sprintf("%s", vv.TargetPort.StrVal)}lanEndPoint += fmt.Sprintf("%s:%s:%s,", vsapp, vport, vv.Protocol)svcPort += fmt.Sprintf("%d,", vv.Port)}if len(svcPort) > 0 {svcPort = svcPort[0 : len(svcPort)-1]}lanEndPoint = lanEndPoint[0 : len(lanEndPoint)-1]}Items := &Service{ServiceName: svc.Name,NameSpace:   svc.Namespace,SvcType:     svcType,SvcIp:       svc.Spec.ClusterIP,Labels:      labelsStr,SvcPort:     svcPort,LanEndpoint: lanEndPoint,WanEndpoint: wanEndPoint,CreateTime:  svc.CreationTimestamp.Format("2006-01-02 15:04:05"),}bbb = append(bbb, *Items)}return bbb, err
}func SvcCreate(kubeconfig string, bodys []byte) error {gp := gjson.ParseBytes(bodys)clusterId := gp.Get("clusterId").String()if kubeconfig == "" {kubeconfig = clusterId}serviceName := gp.Get("serviceName").String()nameSpace := gp.Get("nameSpace").String()svcType := gp.Get("svcType").String()deployName := gp.Get("deployName").String()isHeadless := gp.Get("isHeadless").Strvar labelsMap = make(map[string]string)labelsMap["app"] = serviceNamefor _, vv := range gp.Get("lables").Array() {labelsMap[vv.Get("key").Str] = vv.Get("value").Str}selectApp := serviceNameif deployName != "" {selectApp = deployName}var serviceType corev1.ServiceTypeswitch svcType {case "NodePort":serviceType = corev1.ServiceTypeNodePortcase "LoadBalancer":serviceType = corev1.ServiceTypeLoadBalancerdefault:serviceType = corev1.ServiceTypeClusterIP}if isHeadless == "on" {serviceType = corev1.ServiceTypeClusterIP}svcInstance := &corev1.Service{ObjectMeta: metav1.ObjectMeta{Name:      serviceName,Namespace: nameSpace,Labels:    labelsMap,},Spec: corev1.ServiceSpec{Selector: map[string]string{"app": selectApp,},Type: serviceType,},}if isHeadless == "on" {svcInstance.Spec.ClusterIP = corev1.ClusterIPNone}ports := gp.Get("ports").Array()var svcPorts = make([]corev1.ServicePort, 0)for _, vv := range ports {var svcProtocol corev1.Protocolif vv.Get("protocol").Str == "UDP" {svcProtocol = corev1.ProtocolUDP} else {svcProtocol = corev1.ProtocolTCP}svcPort := &corev1.ServicePort{Name:       vv.Get("portName").Str,Port:       int32(vv.Get("svcPort").Int()),Protocol:   svcProtocol,TargetPort: intstr.FromInt32(int32(vv.Get("targetPort").Int())),}svcPorts = append(svcPorts, *svcPort)}svcInstance.Spec.Ports = svcPortsclientset := common.ClientSet(kubeconfig)_, err := clientset.CoreV1().Services(nameSpace).Create(context.TODO(), svcInstance, metav1.CreateOptions{})if err != nil {return err}return nil
}func SvcYamlModify(kubeconfig string, yamlData []byte) error {data, err := yamlutil.ToJSON(yamlData)if err != nil {return err}service := &corev1.Service{}err = json.Unmarshal(data, service)if err != nil {return err}namespace := service.ObjectMeta.NamespaceserviceName := service.ObjectMeta.Nameclientset := common.ClientSet(kubeconfig)_, err = clientset.CoreV1().Services(namespace).Update(context.TODO(), service, metav1.UpdateOptions{})if err != nil {return err}fmt.Println(namespace, serviceName)return err
}func GetSvcYaml(kubeconfig, namespace, serviceName string) (string, error) {servicesClient := common.ClientSet(kubeconfig).CoreV1().Services(namespace)service, err := servicesClient.Get(context.TODO(), serviceName, metav1.GetOptions{})serviceUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(service)if err != nil {return "", err}yamlBytes, err := yaml.Marshal(serviceUnstructured)if err != nil {return "", err}return string(yamlBytes), nil
}

七.效果图

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3018367.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

【RT-DETR有效改进】 主干篇 | 2024.5全新的移动端网络MobileNetV4改进RT-DETR(含MobileNetV4全部版本改进)

&#x1f451;欢迎大家订阅本专栏&#xff0c;一起学习RT-DETR&#x1f451; 一、本文介绍 本文给大家带来的改进机制是MobileNetV4&#xff0c;其发布时间是2024.5月。MobileNetV4是一种高度优化的神经网络架构&#xff0c;专为移动设备设计。它最新的改动总结主要有两点&…

flutter报错

组件相关 type ‘List’ is not a subtype of type ‘List’ children: CardList.map((item) > Container( 加上 *** < Widget>*** 正常 type ‘(dynamic, dynamic) > Container’ is not a subtype of type ‘(CardType) > Widget’ of ‘f’ children: CardL…

【管理篇】如何提升管理中的沟通效率?

目录标题 管理沟通那些事如何提升沟通效率?&#x1f525;如何提升沟通技能&#xff1f; 向上沟通、员工激励和团队凝聚力提升 是管理沟通上比较难得问题 管理沟通那些事 管理沟通让技术管理者们痛苦的主因是确定性和规则性的减弱&#xff0c;不确定性的大幅度上升&#xff0c…

革新品质检测,质构科技重塑肉类行业新篇章

革新品质检测&#xff0c;质构科技重塑肉类行业新篇章 在现代社会&#xff0c;消费者对食品安全和品质的要求日益提升&#xff0c;特别是在肉类行业。为了满足这一市场需求&#xff0c;质构科技凭借其精准、高效的优势&#xff0c;正逐渐成为肉类品质检测的新星。今天&#xf…

前端传递list(数组)类型参数,后端接收失败

一顿报错,我之前遇到的list都是Long类型 貌似用GET也是可以的,但是很奇怪一直报错 就是不可以 后来去百度 查询到可以用两种方法解决这个问题 1、拆开 传 以GET方式&#xff0c;后端GetMappingRequestParam接收。 2、以Post方式传&#xff0c;后端创建dto PostMappingReques…

【spring】Bean的生命周期回调函数和Bean的循环依赖

目录 1、Bean的生命周期 2、Bean的生命周期回调函数 2.1、初始化的生命周期回调 2.2、销毁的生命周期回调 3、Bean的循环依赖 1、Bean的生命周期 spring的bean的生命周期主要是创建bean的过程&#xff0c;一个bean的生命周期主要是4个步骤&#xff1a;实例化&#xff0c;…

AI时代的就业转型与个人发展

AI时代的就业转型与个人发展&#xff1a;机遇与挑战并存 AI出现的背景&#xff1a;技术革命的浪潮 随着21世纪信息技术的突飞猛进&#xff0c;人工智能&#xff08;Artificial Intelligence, AI&#xff09;作为一场技术革命的产物&#xff0c;正逐渐从科幻小说走向现实世界的…

Pycharm链接远程服务器GPU跑深度学习模型

我们在学习深度学习时&#xff0c;常常会遇到自己笔记本电脑性能不够&#xff0c;显卡性能低&#xff0c;在运行深度学习项目的时候很浪费时间。如果实验室有可用于深度学习的服务器的话&#xff0c;会大大减少代码执行时间&#xff0c;服务器上的GPU算力一般都很高。 本文主要…

密室逃脱游戏-第12届蓝桥杯省赛Python真题精选

[导读]&#xff1a;超平老师的Scratch蓝桥杯真题解读系列在推出之后&#xff0c;受到了广大老师和家长的好评&#xff0c;非常感谢各位的认可和厚爱。作为回馈&#xff0c;超平老师计划推出《Python蓝桥杯真题解析100讲》&#xff0c;这是解读系列的第58讲。 密室逃脱游戏&…

Unity与C#的关系

第一&#xff0c;我们首先需要知道Unity与C#的关系是什么&#xff1f; 第二&#xff0c;我们要明白为什么Unity会使用C#&#xff0c;而不是C&#xff1f; 第三&#xff0c;我们需要知道Unity是怎么使用C#的&#xff1f; 第一点&#xff1a; 先说结论&#xff1a;C#是Unity用…

Linux性能压测指标信息

1、CPU使用 服务器CPU整体负载信息 可以查看top命令输出的第三行数据 查看多核CPU命令 mpstat -P ALL 和 sar -P ALL top命令执行后输入1 2、内存使用 top命令或者free命令来查看内存的信息&#xff0c;第一行是物理内存使用&#xff0c;第二行是虚拟内存使用(交换空间)。…

mvc 异步请求、异步连接、异步表单

》》》 利用Jquery ajax 》》》 mvc 异步表单 c# MVC 添加异步 jquery.unobtrusive-ajax.min.js 方法 具–>Nuget程序包管理器–>程序包管理器控制台 在控制台输入&#xff1a;PM>Install-Package Microsoft.jQuery.Unobtrusive.Ajax –version 3.0.0 回车执行即可在…

多C段的美国站群服务器有什么用途?

多C段的美国站群服务器有什么用途? 多C段的美国站群服务器是一种常见的网络运营策略&#xff0c;其用途主要体现在以下几个方面&#xff1a; 多C段的美国站群服务器有什么用途? 1. 提高站点排名和流量 部署多个站点在不同的C段IP地址上&#xff0c;可以通过不同的IP地址发布…

AI视频教程下载:学会用AI创作文本图片音频视频

在不断发展的科技领域&#xff0c;人工智能 (AI) 是毋庸置疑的冠军&#xff0c;它是一种不断创新的力量&#xff0c;在我们的生活中扮演着越来越重要的角色。随着 2023 年的到来&#xff0c;我们诚挚地欢迎您加入人工智能精通课程的大门。 这不仅仅是一个课程&#xff0c;它专为…

docker部署elasticsearch7.7.0级拼音(pinyin)插件和分词(ik)插件

拉取并启动es docker run -d --namees -p 9200:9200 -p 9300:9300 -e "discovery.typesingle-node" elasticsearch:7.7.0安装pinyin插件 下载pinyin插件 下载ik插件 上传插件到服务器 docker cp /path/to/elasticsearch-analysis-pinyin-7.7.0.zip elasticsearch…

【Pytorch】5.DataLoder的使用

什么是DataLoader 个人理解是&#xff0c;如果Dataset的所有数据相当于一副扑克牌&#xff0c;DataLoader就相当于从扑克牌中抽取几张&#xff0c;我们可以规定一次抽取的张数&#xff0c;或者以什么规则进行抽取 DataLoader的使用 查阅官网的文档&#xff0c;主要有这几个参数…

libcity笔记:详细流程(以DeepMove为例)

1 主调用 python run_model.py --task traj_loc_pred --model DeepMove --dataset gowalla --batch_size5有task、dataset、model三个必须命令行参数batch_size一个可选命令行参数没有confg_file 1.1 libcity/utils/argument_list.py/str2bool 将字符串表示的布尔值转换为 Pyt…

C++字模软件发送 单片机接收显示

/****先定义数组类型再赋值**L310*********/ /*2014 8 21 10:01**PAST*CODE1000**TEST**/ #include<reg51.h> #define uint unsigned int #define uchar unsigned char sfr AUXR0x8e; //辅助寄存器 sfr SADDR0xA9; …

java之web笔记

1.Servlet技术 1.1 JavaWeb概述 在Sun的Java Servlet规范中&#xff0c;对Java Web应用作了这样定义:“JavaWeb应用由一组Servlet、HTML页、类、以及其它可以被绑定的资源构成。它可以在各种供应商提供的实现Servlet规范的Servlet容器中运行。 Java Web应用中可以包含如下内容…

OpenGrok使用

以前都是用的find&#xff0c;或者VScode里面的浏览&#xff0c;但是到了Android这个就不行了&#xff0c;代码太多了。都在用OpenGrok&#xff0c;所以俺也用一下。 这里有两个步骤&#xff0c;一个是安装&#xff0c;是一个使用。 1 安装 大概看了一下&#xff0c;安装是to…