【k8s多集群管理平台开发实践】六、client-go实现k8s的cronjob的列表、创建cronjob、yaml配置更新

news/2024/10/22 8:22:42/

文章目录

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

简介

本章节主要讲解通过client-go实现cronjob的列表显示、界面创建cronjob,读取yaml配置并更改。功能主要有后端部分:控制器代码、模型部分代码、路由配置。前端部分:cronjobList.html的html代码,cronjobCreate.html,cronjobYaml.html这几部分代码组成。

一.cronjob的列表实现

1.1.controllers控制器代码

该列表支持传递集群ID、命名空间、cronjob名称来进行过滤查询

golang">func (this *CronjobController) List() {clusterId := this.GetString("clusterId")nameSpace := this.GetString("nameSpace")cronjobName := this.GetString("cronjobName")labels := this.GetString("labels")labelsKV := strings.Split(labels, ":")var labelsKey, labelsValue stringif len(labelsKV) == 2 {labelsKey = labelsKV[0]labelsValue = labelsKV[1]}dxList, err := m.CronjobList(clusterId, nameSpace, cronjobName, labelsKey, labelsValue)msg := "success"code := 0count := len(dxList)if err != nil {log.Printf("[ERROR] CronjobList error:%s \n", err)msg = err.Error()code = -1}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg, "count": count, "data": &dxList}//this.Data["json"] = &datasthis.ServeJSON()
}
1.2.models模型代码

先定义一个结构体Cronjob将需要显示的信息整理出来,然后通过common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace).List 读取出cronjob的列表,并将需要的信息赋值到结构体Cronjob,并追加到结构体列表var bbb = make([]Cronjob, 0),注意所使用的api版本,版本高于1.26的就用v1版本,否则用V1beta1.

golang">type Cronjob struct {CronjobName      string `json:"cronjobName"`NameSpace        string `json:"nameSpace"`Labels           string `json:"labels"`Annotations      string `json:"annotations"`ImgUrl           string `json:"imgUrl"`Suspend          string `json:"suspend"`Schedule         string `json:"schedule"`Active           int    `json:"active"`CreateTime       string `json:"createTime"`LastScheduleTime string `json:"lastScheduleTime"`
}func CronjobList(kubeconfig, namespace, cronjobName string, labelsKey, labelsValue string) ([]Cronjob, error) {if namespace == "" {//namespace = corev1.NamespaceDefaultnamespace = corev1.NamespaceAll}var bbb = make([]Cronjob, 0)//设置标签过滤的ListOptionsvar listOptions = metav1.ListOptions{}if labelsKey != "" && labelsValue != "" {listOptions = metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", labelsKey, labelsValue),}}//BatchV1 会提示the server could not find the requested resource,改成BatchV1beta1 后正常,注意k8s版本,大于1.26的就用v1版本//xList, err := common.ClientSet(kubeconfig).BatchV1beta1().CronJobs(namespace).List(context.TODO(), listOptions)xList, err := common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace).List(context.TODO(), listOptions) if err != nil {log.Printf("[ERROR] ListCronjobError err:%v", err)return bbb, err}for _, vv := range xList.Items {//根据名称过滤if cronjobName != "" {if !strings.Contains(vv.Name, cronjobName) {continue}}var labelsStr, imgUrlStr stringfor k1, v1 := range vv.ObjectMeta.Labels {labelsStr += fmt.Sprintf("%s:%s,", k1, v1)}if len(labelsStr) > 0 {labelsStr = labelsStr[0 : len(labelsStr)-1]}for _, v2 := range vv.Spec.JobTemplate.Spec.Template.Spec.Containers {imgUrlStr += fmt.Sprintf("%s,", v2.Image)}if len(imgUrlStr) > 0 {imgUrlStr = imgUrlStr[0 : len(imgUrlStr)-1]}var lastScheduleTime stringif vv.Status.LastScheduleTime != nil {lastScheduleTime = vv.Status.LastScheduleTime.Format("2006-01-02 15:04:05")}xItems := &Cronjob{CronjobName: vv.Name,NameSpace:   vv.Namespace,Labels:      labelsStr,ImgUrl:      imgUrlStr,Suspend:     fmt.Sprintf("%v", *vv.Spec.Suspend),Schedule:    vv.Spec.Schedule,Active:      len(vv.Status.Active),CreateTime:  vv.CreationTimestamp.Format("2006-01-02 15:04:05"),//LastScheduleTime: vv.Status.LastScheduleTime.Format("2006-01-02 15:04:05"),LastScheduleTime: lastScheduleTime,}bbb = append(bbb, *xItems)}return bbb, err
}

二.界面创建cronjob

2.1.controllers控制器代码

控制器函数接收前端html的表单传递过来的json 请求头,并传递给模型中的函数CronjobCreate来处理。

golang">func (this *CronjobController) Create() {clusterId := this.GetString("clusterId")code := 0msg := "success"log.Println(string(this.Ctx.Input.RequestBody))err := m.CronjobCreate(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模分代码

通过控制器部分传递过来的body内容,进行json解析。首先创建一个 cronjob := &batchv1.CronJob{cronjob的结构体,然后将解析json的值赋值到结构体,并调用Create(context.TODO(), cronjob, metav1.CreateOptions{}) 函数进行创建。

golang">func CronjobCreate(kubeconfig string, bodys []byte) error {//解析json并取出相关值gp := gjson.ParseBytes(bodys)clusterId := gp.Get("clusterId").String()if kubeconfig == "" {kubeconfig = clusterId}cronjobName := gp.Get("cronjobName").String()nameSpace := gp.Get("nameSpace").String()var pullPolicy corev1.PullPolicyimagePullPolicy := gp.Get("imagePullPolicy").String()switch imagePullPolicy {case "Never":pullPolicy = corev1.PullNevercase "IfNotPresent":pullPolicy = corev1.PullIfNotPresentdefault:pullPolicy = corev1.PullAlways}imageUrl := gp.Get("imageUrl").String()resourceLimitCheck := gp.Get("resourceLimitCheck").String()periodCheck := gp.Get("periodCheck").String()taskSetCheck := gp.Get("taskSetCheck").String()schedule := gp.Get("schedule").String()if schedule == "" {schedule = "* * * * *"}labelsMap := map[string]string{"app": cronjobName,}for _, vv := range gp.Get("lables").Array() {labelsMap[vv.Get("key").String()] = vv.Get("value").String()}//定义一个cronjob的实例,然后进行赋值,cronjob := &batchv1.CronJob{ObjectMeta: metav1.ObjectMeta{Name:      cronjobName,Namespace: nameSpace,Labels:    labelsMap,},Spec: batchv1.CronJobSpec{Schedule: schedule, // 定时任务表达式JobTemplate: batchv1.JobTemplateSpec{Spec: batchv1.JobSpec{ //v1版本有JobSpec,beta1版本没有Template: corev1.PodTemplateSpec{Spec: corev1.PodSpec{Containers: []corev1.Container{{Name:            cronjobName,Image:           imageUrl,ImagePullPolicy: pullPolicy,},},RestartPolicy: corev1.RestartPolicyNever,},},},},},}commandStr := gp.Get("command").Strif commandStr != "" {commandArry := strings.Split(commandStr, ",")cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command = commandArry}argsStr := gp.Get("args").Strif argsStr != "" {argsArry := strings.Split(argsStr, ",")cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args = argsArry}//将定义的cronjob实例进行创建jobClient := common.ClientSet(kubeconfig).BatchV1().CronJobs(nameSpace)_, err := jobClient.Create(context.TODO(), cronjob, metav1.CreateOptions{})if err != nil {return err}return nil
}

三.读取cronjob的yaml配置并更新

3.1.controllers控制器代码

通过传递的集群名称、命名空间、cronjob的名称通过GetCronjobYaml函数处理

golang">//读取yaml配置
func (this *CronjobController) Yaml() {clusterId := this.GetString("clusterId")namespace := this.GetString("nameSpace")cronjobName := this.GetString("cronjobName")yamlStr, _ := m.GetCronjobYaml(clusterId, namespace, cronjobName)this.Ctx.WriteString(yamlStr)
}//更新yaml配置
func (this *CronjobController) ModifyByYaml() {clusterId := this.GetString("clusterId")code := 0msg := "success"bodyByte := []byte(strings.ReplaceAll(string(this.Ctx.Input.RequestBody), "%25", "%"))err := m.CronjobYamlModify(clusterId, bodyByte)if err != nil {code = -1msg = err.Error()log.Printf("[ERROR] cronjob ModifyByYaml Fail:%s\n", err)}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg}this.ServeJSON()
}
3.2.models模型代码

该列表可以通过传递

golang">//读取cronjob实例并转化成yaml配置文件
func GetCronjobYaml(kubeconfig, namespace, cronjobName string) (string, error) {jobClient := common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace)jobInstance, err := jobClient.Get(context.TODO(), cronjobName, metav1.GetOptions{})//将cronjob实例进行解构jobUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(jobInstance)if err != nil {return "", err}//并将解构后的数据序列化成yaml格式yamlBytes, err := yaml.Marshal(jobUnstructured)if err != nil {return "", err}//fmt.Println(string(yamlBytes))return string(yamlBytes), nil
}//更新yaml配置
func CronjobYamlModify(kubeconfig string, yamlData []byte) error {data, err := yamlutil.ToJSON(yamlData)if err != nil {return err}cronjob := &batchv1.CronJob{}//将读取的yaml配置反序列化成cronjob实例err = json.Unmarshal(data, cronjob)if err != nil {return err}//调用Update函数更新namespace := cronjob.ObjectMeta.Namespace//cronjobName := cronjob.ObjectMeta.NamejobClient := common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace)_, err = jobClient.Update(context.TODO(), cronjob, metav1.UpdateOptions{})return err
}

四.路由设置

4.1.路由设置

将这段代码添加到routers/route.go中

golang">	//cronjobbeego.Router("/xkube/cronjob/v1/List", &controllers.CronjobController{}, "*:List")beego.Router("/xkube/cronjob/v1/Create", &controllers.CronjobController{}, "*:Create")beego.Router("/xkube/cronjob/v1/ModifyByYaml", &controllers.CronjobController{}, "*:ModifyByYaml")beego.Router("/xkube/cronjob/v1/Yaml", &controllers.CronjobController{}, "*:Yaml")

五.前端代码

5.1.列表部分html代码

5.1 cronjobList.html

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>cronjob列表</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: 15px !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="createCronjob"><i class="layui-icon">&#xe61f;</i>创建cronjob</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="ImgTpl">{{# if (d.imgUrl != "") { }}{{# layui.each(d.imgUrl.split(','), function(index, item){ }}{{# if(index == 0) { }}<span>{{ item }}</span>{{# }else{ }}<br><span>{{ item }}</span>{{# } }}  {{# });  }}{{# }else{  }}<span></span>{{# } }}
</script>	
<script type="text/html" id="suspendTpl">{{# if ( d.suspend == 'false' ) { }}<span style="color:#218868">{{ d.suspend}}</span>{{# } else { }}<span style="color:#FF5722">{{ d.suspend}}</span>
{{# } }}
</script>
<script type="text/html" id="sactiveTpl">{{# if ( d.active > 0 ) { }}<span style="color:#218868">d.active</span>{{# } else { }}<span style="color:#FF5722">{{ d.active}}</span>
{{# } }}
</script>
<script>var clusterId = getQueryString("clusterId");
if (clusterId == null) {clusterId = getCookie("clusterId")
}var cronjobApi = "v1";layui.use(['form', 'table','miniTab'], function () {var $ = layui.jquery,form = layui.form,table = layui.table;miniTab = layui.miniTab,miniTab.listen();form.render();table.render({elem: '#currentTableId',initSort: {field:'createTime', type:'desc'},url: '/cronjob/'+cronjobApi+'/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: 'cronjobName', title: '名称'},{field: 'nameSpace', title: '命名空间', sort: true},{field: 'labes', title: '标签', sort: true,templet: '#TagTpl',hide:true},{field: 'imgUrl', title: '镜像地址', sort: true,templet: '#ImgTpl'},{field: 'suspend',  title: '暂停', sort: true,templet: '#suspendTpl'},{field: 'schedule', minWidth: 200, title: '计划', sort: true},{field: 'active',title: '活跃',width:120, sort: true,templet: '#activeTpl'},{field: 'createTime', title: '创建时间',hide:true},{field: 'lastScheduleTime', width:180, title: '最近调度'},{title: '操作', minWidth: 360, toolbar: '#currentTableBar', align: "center"}]],//size:'lg',limits: [25, 50, 100],limit: 25,page: true});/*** toolbar监听事件*/table.on('toolbar(currentTableFilter)', function (obj) {if (obj.event === 'createCronjob') {  // 监听添加操作var index = layer.open({title: '创建',type: 2,shade: 0.2,maxmin:true,shadeClose: true,area: ['60%', '90%'],content: '/page/xkube/cronjobCreate.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/cronjobYaml.html?clusterId='+clusterId+'&nameSpace='+data.nameSpace+'&cronjobName='+data.cronjobName,});$(window).on("resize", function () {layer.full(index);});return false;}});});
</script>
</html>
5.2.创建表单html代码

5.2 cronjobCreate.html

<!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"><blockquote class="layui-elem-quote layui-text">帮助中心:<a href="#" target="_blank">添加说明文档</a></blockquote><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></div></div><div class="layui-form-item"><label class="layui-form-label required">名称</label><div class="layui-input-inline"><input type="text" name="cronjobName"  lay-verify="required" lay-reqtext="不能为空"  placeholder="不能为空" value="" class="layui-input"></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 class="layui-form-mid layui-word-aux"><span style="color:red">*</span></div></div><div class="layui-form-item"><label class="layui-form-label">镜像策略</label><div class="layui-input-block"><input type="radio" name="imagePullPolicy" value="Always" title="Always" checked=""><input type="radio" name="imagePullPolicy" value="IfNotPresent" title="IfNotPresent"><input type="radio" name="imagePullPolicy" value="Never" title="Never"></div></div><div class="layui-form-item"><label class="layui-form-label required">镜像地址</label><div class="layui-input-inline" style="width:380px"><input type="text" name="imageUrl"  lay-verify="required" lay-reqtext="不能为空"  placeholder="不能为空" value="" class="layui-input"></div><div class="layui-form-mid layui-word-aux"><span style="color:red">*</span></div></div><div class="layui-form-item"><label class="layui-form-label">定时规则</label><div class="layui-input-inline" style="width:380px">  <input type="text" name="schedule" placeholder="* * * * *" lay-verify="required" lay-reqtext="不能为空" value="" class="layui-input"></div><div class="layui-form-mid layui-word-aux"><span style="color:red">*</span></div>              </div><div class="layui-form-item"><label class="layui-form-label required">启动执行</label><div class="layui-input-inline"><input type="text" name="command" placeholder="命令" value="" class="layui-input"></div><div class="layui-input-inline"><input type="text" name="args" placeholder="参数" value="" class="layui-input"></div></div><div class="labelsTpl"><div class="layui-form-item"><label class="layui-form-label">标签</label><div class="layui-input-inline">  <input type="text" id="labels_key0" name="labels_key[]" placeholder="key" value="" class="layui-input"></div><div class="layui-input-inline">  <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" style="width:100px" id="newaddbtn"><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) {$("#tpl-"+id).remove();TplIndex--;}var clusterId = getQueryString("clusterId");
if (clusterId == null) {clusterId = getCookie("clusterId")
}var cronjobApi = "v1";layui.use(['form'], function () {var form = layui.form,layer = layui.layer,$ = layui.$;//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">' +'<input type="text" name="labels_key[]" id="labels_key'+TplIndex+'" placeholder="key" value="" class="layui-input">' +'</div>' +    '<div class="layui-input-inline">' +  '<input type="text" name="labels_value[]" id="labels_value'+TplIndex+'" placeholder="value" value="" class="layui-input">' +'</div>' +'<div class="layui-input-inline">' +  '<input class="layui-btn layui-btn-normal layui-bg-orange layui-icon" style="width:100px" type="button" id="newDelbtn" value="&#xe616;" οnclick="delTpl('+TplIndex+');" />' +'</div>' +                '</div>'$('.labelsTpl').append(addTpl);   form.render(); return false;   });//监听提交form.on('submit(saveBtn)', function (data) {data.field.cronjobName = data.field.cronjobName.replace(/^\s*|\s*$/g,""); //替换空格data.field.imageUrl = data.field.imageUrl.replace(/^\s*|\s*$/g,""); //替换空格data.field.command = data.field.command.replace(/,|\s|;|\r|\n/g,",");//将空格等符号替换成逗号data.field.args = data.field.args.replace(/,|\s|;|\r|\n/g,",");//将空格等符号替换成逗号//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;}//console.log(data.field);layer.confirm('确定添加?', {icon: 3, title:'提示',yes: function(index){var index2 = layer.load(0, {shade: false});layer.msg('稍等片刻');$.ajax({url: '/cronjob/'+cronjobApi+'/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>
</html>
5.3.显示yaml配置的html代码

5.3 cronjobYaml.html

<!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">下载</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>var clusterId = getQueryString("clusterId");
if (clusterId == null) {clusterId = getCookie("clusterId")
}var cronjobApi = "v1";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: '/cronjob/'+cronjobApi+'/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: '/cronjob/'+cronjobApi+'/ModifyByYaml'+location.search,type: "POST",data: yamlBody,dataType: "json",success: function (resp) {layer.msg(resp.msg);}});},cancel: function(index, layero){ layer.close(index);} });});});
</script></body>
</html>

六.完整代码

6.1.控制器完整代码

6.1 cronjob.go,放到controllers下

golang">// cronjob.go
package controllersimport ("log"m "myk8s/models""strings"beego "github.com/beego/beego/v2/server/web"//"github.com/tidwall/gjson"
)type CronjobController struct {beego.Controller
}func (this *CronjobController) List() {clusterId := this.GetString("clusterId")nameSpace := this.GetString("nameSpace")cronjobName := this.GetString("cronjobName")labels := this.GetString("labels")labelsKV := strings.Split(labels, ":")var labelsKey, labelsValue stringif len(labelsKV) == 2 {labelsKey = labelsKV[0]labelsValue = labelsKV[1]}dxList, err := m.CronjobList(clusterId, nameSpace, cronjobName, labelsKey, labelsValue)msg := "success"code := 0count := len(dxList)if err != nil {log.Printf("[ERROR] CronjobList error:%s \n", err)msg = err.Error()code = -1}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg, "count": count, "data": &dxList}//this.Data["json"] = &datasthis.ServeJSON()
}func (this *CronjobController) Create() {clusterId := this.GetString("clusterId")code := 0msg := "success"log.Println(string(this.Ctx.Input.RequestBody))err := m.CronjobCreate(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 *CronjobController) ModifyByYaml() {clusterId := this.GetString("clusterId")code := 0msg := "success"bodyByte := []byte(strings.ReplaceAll(string(this.Ctx.Input.RequestBody), "%25", "%"))err := m.CronjobYamlModify(clusterId, bodyByte)if err != nil {code = -1msg = err.Error()log.Printf("[ERROR] cronjob ModifyByYaml Fail:%s\n", err)}this.Data["json"] = &map[string]interface{}{"code": code, "msg": msg}this.ServeJSON()
}func (this *CronjobController) Yaml() {clusterId := this.GetString("clusterId")namespace := this.GetString("nameSpace")cronjobName := this.GetString("cronjobName")yamlStr, _ := m.GetCronjobYaml(clusterId, namespace, cronjobName)this.Ctx.WriteString(yamlStr)
}
6.2.模型完整代码

6.2 cronjobModel.go放到models下

golang">// cronjobModel.go
package modelsimport ("context""encoding/json""fmt""log""myk8s/common""strings""github.com/tidwall/gjson""sigs.k8s.io/yaml"yamlutil "k8s.io/apimachinery/pkg/util/yaml"batchv1 "k8s.io/api/batch/v1" //注意有的地方要用beta1版本才行corev1 "k8s.io/api/core/v1""k8s.io/apimachinery/pkg/api/resource"metav1 "k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/apimachinery/pkg/runtime"
)type Cronjob struct {CronjobName      string `json:"cronjobName"`NameSpace        string `json:"nameSpace"`Labels           string `json:"labels"`Annotations      string `json:"annotations"`ImgUrl           string `json:"imgUrl"`Suspend          string `json:"suspend"`Schedule         string `json:"schedule"`Active           int    `json:"active"`CreateTime       string `json:"createTime"`LastScheduleTime string `json:"lastScheduleTime"`
}func CronjobList(kubeconfig, namespace, cronjobName string, labelsKey, labelsValue string) ([]Cronjob, error) {if namespace == "" {//namespace = corev1.NamespaceDefaultnamespace = corev1.NamespaceAll}var bbb = make([]Cronjob, 0)//设置ListOptionsvar listOptions = metav1.ListOptions{}if labelsKey != "" && labelsValue != "" {listOptions = metav1.ListOptions{LabelSelector: fmt.Sprintf("%s=%s", labelsKey, labelsValue),}}//BatchV1 会提示the server could not find the requested resource,改成BatchV1beta1 后正常//xList, err := common.ClientSet(kubeconfig).BatchV1beta1().CronJobs(namespace).List(context.TODO(), listOptions) //zx-pcauto ok,yt-pcauto异常:the server could not find the requested resourcexList, err := common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace).List(context.TODO(), listOptions) //yt-pcauto ok,zx-pcauto 异常:the server could not find the requested resourceif err != nil {log.Printf("[ERROR] ListCronjobError err:%v", err)return bbb, err}for _, vv := range xList.Items {//搜索if cronjobName != "" {if !strings.Contains(vv.Name, cronjobName) {continue}}var labelsStr, imgUrlStr stringfor k1, v1 := range vv.ObjectMeta.Labels {labelsStr += fmt.Sprintf("%s:%s,", k1, v1)}if len(labelsStr) > 0 {labelsStr = labelsStr[0 : len(labelsStr)-1]}for _, v2 := range vv.Spec.JobTemplate.Spec.Template.Spec.Containers {imgUrlStr += fmt.Sprintf("%s,", v2.Image)}if len(imgUrlStr) > 0 {imgUrlStr = imgUrlStr[0 : len(imgUrlStr)-1]}var lastScheduleTime stringif vv.Status.LastScheduleTime != nil {lastScheduleTime = vv.Status.LastScheduleTime.Format("2006-01-02 15:04:05")}xItems := &Cronjob{CronjobName: vv.Name,NameSpace:   vv.Namespace,Labels:      labelsStr,ImgUrl:      imgUrlStr,Suspend:     fmt.Sprintf("%v", *vv.Spec.Suspend),Schedule:    vv.Spec.Schedule,Active:      len(vv.Status.Active),CreateTime:  vv.CreationTimestamp.Format("2006-01-02 15:04:05"),//LastScheduleTime: vv.Status.LastScheduleTime.Format("2006-01-02 15:04:05"),LastScheduleTime: lastScheduleTime,}bbb = append(bbb, *xItems)}return bbb, err
}func CronjobCreate(kubeconfig string, bodys []byte) error {gp := gjson.ParseBytes(bodys)clusterId := gp.Get("clusterId").String()if kubeconfig == "" {kubeconfig = clusterId}cronjobName := gp.Get("cronjobName").String()nameSpace := gp.Get("nameSpace").String()var pullPolicy corev1.PullPolicyimagePullPolicy := gp.Get("imagePullPolicy").String()switch imagePullPolicy {case "Never":pullPolicy = corev1.PullNevercase "IfNotPresent":pullPolicy = corev1.PullIfNotPresentdefault:pullPolicy = corev1.PullAlways}imageUrl := gp.Get("imageUrl").String()resourceLimitCheck := gp.Get("resourceLimitCheck").String()periodCheck := gp.Get("periodCheck").String()taskSetCheck := gp.Get("taskSetCheck").String()schedule := gp.Get("schedule").String()if schedule == "" {schedule = "* * * * *"}labelsMap := map[string]string{"app": cronjobName,}for _, vv := range gp.Get("lables").Array() {labelsMap[vv.Get("key").String()] = vv.Get("value").String()}cronjob := &batchv1.CronJob{ObjectMeta: metav1.ObjectMeta{Name:      cronjobName,Namespace: nameSpace,Labels:    labelsMap,},Spec: batchv1.CronJobSpec{Schedule: schedule, // 定时任务表达式JobTemplate: batchv1.JobTemplateSpec{Spec: batchv1.JobSpec{ //v1版本有JobSpec,beta1版本没有Template: corev1.PodTemplateSpec{Spec: corev1.PodSpec{Containers: []corev1.Container{{Name:            cronjobName,Image:           imageUrl,ImagePullPolicy: pullPolicy,},},RestartPolicy: corev1.RestartPolicyNever,},},},},},}commandStr := gp.Get("command").Strif commandStr != "" {commandArry := strings.Split(commandStr, ",")cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Command = commandArry}argsStr := gp.Get("args").Strif argsStr != "" {argsArry := strings.Split(argsStr, ",")cronjob.Spec.JobTemplate.Spec.Template.Spec.Containers[0].Args = argsArry}jobClient := common.ClientSet(kubeconfig).BatchV1().CronJobs(nameSpace)_, err := jobClient.Create(context.TODO(), cronjob, metav1.CreateOptions{})if err != nil {return err}return nil
}func CronjobYamlModify(kubeconfig string, yamlData []byte) error {data, err := yamlutil.ToJSON(yamlData)if err != nil {return err}cronjob := &batchv1.CronJob{}err = json.Unmarshal(data, cronjob)if err != nil {return err}namespace := cronjob.ObjectMeta.Namespace//cronjobName := cronjob.ObjectMeta.NamejobClient := common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace)_, err = jobClient.Update(context.TODO(), cronjob, metav1.UpdateOptions{})return err
}func GetCronjobYaml(kubeconfig, namespace, cronjobName string) (string, error) {jobClient := common.ClientSet(kubeconfig).BatchV1().CronJobs(namespace)jobInstance, err := jobClient.Get(context.TODO(), cronjobName, metav1.GetOptions{})jobUnstructured, err := runtime.DefaultUnstructuredConverter.ToUnstructured(jobInstance)if err != nil {return "", err}yamlBytes, err := yaml.Marshal(jobUnstructured)if err != nil {return "", err}//fmt.Println(string(yamlBytes))return string(yamlBytes), nil
}

七.效果图

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


http://www.ppmy.cn/news/1457789.html

相关文章

【强训笔记】day13

NO.1 代码实现&#xff1a; #include <iostream>#include<string>using namespace std;int n,k,t; string s;int func() {int ret0;for(int i0;i<n;i){char chs[i];if(chL) ret-1;else{if(i-1>0&&i-2>0&&s[i-1]W&&s[i-2]W) retk…

武汉星起航:亚马逊:跨境电商领军平台,中国卖家全球拓展的首选

2015年&#xff0c;亚马逊全球开店业务正式进入中国&#xff0c;为中国卖家带来了全新的跨境电商机遇。如今&#xff0c;亚马逊已在全球拥有包括美国、加拿大、墨西哥、英国、法国、德国等在内的17大海外站点&#xff0c;为中国卖家提供了广阔的销售市场。武汉星起航将详细探讨…

Web Component fancy-components

css-doodle 组件库 fancy-components 组件库使用 yarn add fancy-components使用&#xff1a; import { FcBubbles } from fancy-components new FcBubbles() //要用哪个就new哪个 new 这里可能会报错eslink,eslintrc.js中处理报错 module.exports {rules: {no-new: off} …

嵌入式人工智能应用-第三章 opencv操作1

一 函数的基本操作 1.1 图像的存取和显示 有多种方式从现实世界中获取数字图像&#xff1a;数码相机&#xff0c;扫描仪&#xff0c;计算机断层扫描和磁共振成像等等。在任何情况下&#xff0c;人类看到的都是图像。然而&#xff0c;当将其转换为数字设备时&#xff0c;数字设…

ubuntu20部署3d高斯

3d高斯的链接&#xff1a;https://github.com/graphdeco-inria/gaussian-splatting 系统环境 ubuntu20的系统环境&#xff0c;打算只运行训练的代码&#xff0c;而不去进行麻烦的可视化&#xff0c;可视化直接在windows上用他们预编译好的exe去可视化。&#xff08;因为看的很…

tracert命令

Tracert&#xff08;跟踪路由&#xff09;是路由跟踪实用程序&#xff0c;用于确定IP数据报访问目标所采取的路径。Tracert命令用IP生存时间&#xff08;TTL&#xff09;字段和ICMP错误消息&#xff0c;来确定从一个主机到网络上其他主机的路由。 命令格式&#xff1a;tracert …

中国棋手再夺世界桂冠,李轩豪问鼎第五届梦百合杯世界围棋公开赛

5月4日,第五届“MLILY梦百合0压床垫杯”世界围棋公开赛决赛在江苏省如皋市圆满结束,中国棋手党毅飞和李轩豪展开巅峰对决,最终,李轩豪执白168手战胜党毅飞,以3比1的比分夺得桂冠并获得由MLILY梦百合赞助的180万冠军奖金,这是李轩豪个人职业生涯中首次问鼎世界冠军,成为世界棋坛…

Redis是什么? 日常运维 Redis 需要注意什么 ? 怎么降低Redis 内存使用 节省内存?

你的项目或许已经使用 Redis 很长时间了&#xff0c;但在使用过程中&#xff0c;你可能还会或多或少地遇到以下问题&#xff1a; 我的 Redis 内存为什么增长这么快&#xff1f;为什么我的 Redis 操作延迟变大了&#xff1f;如何降低 Redis 故障发生的频率&#xff1f;日常运维…