mirror of https://github.com/shunfei/cronsun
parent
75b49bddae
commit
7c61222b68
|
@ -31,13 +31,20 @@ var UpgradeCmd = &cobra.Command{
|
|||
ea.Exit("invalid version number")
|
||||
}
|
||||
|
||||
nodesById := getIPMapper(ea)
|
||||
if prever < "0.3.0" {
|
||||
fmt.Println("upgrading data to version 0.3.0")
|
||||
nodesById := getIPMapper(ea)
|
||||
if to_0_3_0(ea, nodesById) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if prever < "0.3.1" {
|
||||
fmt.Println("upgrading data to version 0.3.1")
|
||||
if to_0_3_1(ea, nodesById) {
|
||||
return
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -133,9 +140,7 @@ func to_0_3_0(ea *ExitAction, nodesById map[string]*cronsun.Node) (shouldStop bo
|
|||
for ip, node := range nodesById {
|
||||
_, err = c.UpdateAll(bson.M{"node": ip}, bson.M{"$set": bson.M{"node": node.ID, "hostname": node.Hostname}})
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
fmt.Println("failed to upgrade job logs: ", err.Error())
|
||||
}
|
||||
fmt.Println("failed to upgrade job logs: ", err.Error())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
@ -148,9 +153,38 @@ func to_0_3_0(ea *ExitAction, nodesById map[string]*cronsun.Node) (shouldStop bo
|
|||
for ip, node := range nodesById {
|
||||
_, err = c.UpdateAll(bson.M{"node": ip}, bson.M{"$set": bson.M{"node": node.ID, "hostname": node.Hostname}})
|
||||
if err != nil {
|
||||
if err != nil {
|
||||
fmt.Println("failed to upgrade job latest logs: ", err.Error())
|
||||
}
|
||||
fmt.Println("failed to upgrade job latest logs: ", err.Error())
|
||||
break
|
||||
}
|
||||
}
|
||||
shouldStop = true
|
||||
return err
|
||||
})
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// to_0_3_0 can be run many times
|
||||
func to_0_3_1(ea *ExitAction, nodesById map[string]*cronsun.Node) (shouldStop bool) {
|
||||
// upgrade logs
|
||||
var err error
|
||||
cronsun.GetDb().WithC(cronsun.Coll_JobLog, func(c *mgo.Collection) error {
|
||||
for _, node := range nodesById {
|
||||
_, err = c.UpdateAll(bson.M{"node": node.ID}, bson.M{"$set": bson.M{"ip": node.IP}})
|
||||
if err != nil {
|
||||
fmt.Println("failed to upgrade job logs: ", err.Error())
|
||||
break
|
||||
}
|
||||
}
|
||||
shouldStop = true
|
||||
return err
|
||||
})
|
||||
|
||||
cronsun.GetDb().WithC(cronsun.Coll_JobLatestLog, func(c *mgo.Collection) error {
|
||||
for _, node := range nodesById {
|
||||
_, err = c.UpdateAll(bson.M{"node": node.ID}, bson.M{"$set": bson.M{"ip": node.IP}})
|
||||
if err != nil {
|
||||
fmt.Println("failed to upgrade job latest logs: ", err.Error())
|
||||
break
|
||||
}
|
||||
}
|
||||
|
|
5
job.go
5
job.go
|
@ -69,6 +69,7 @@ type Job struct {
|
|||
// 执行任务的结点,用于记录 job log
|
||||
runOn string
|
||||
hostname string
|
||||
ip string
|
||||
// 用于存储分隔后的任务
|
||||
cmd []string
|
||||
// 控制同时执行任务数
|
||||
|
@ -186,9 +187,9 @@ func (j *Job) unlimit() {
|
|||
atomic.AddInt64(j.Count, -1)
|
||||
}
|
||||
|
||||
func (j *Job) Init(nodeID, hostname string) {
|
||||
func (j *Job) Init(nodeID, hostname, ip string) {
|
||||
var c int64
|
||||
j.Count, j.runOn, j.hostname = &c, nodeID, hostname
|
||||
j.Count, j.runOn, j.hostname, j.ip = &c, nodeID, hostname, ip
|
||||
}
|
||||
|
||||
func (c *Cmd) lockTtl() int64 {
|
||||
|
|
|
@ -25,6 +25,7 @@ type JobLog struct {
|
|||
Name string `bson:"name" json:"name"` // 任务名称
|
||||
Node string `bson:"node" json:"node"` // 运行此次任务的节点 id,索引
|
||||
Hostname string `bson:"hostname" json:"hostname"` // 运行此次任务的节点主机名称,索引
|
||||
IP string `bson:"ip" json:"ip"` // 运行此次任务的节点主机IP,索引
|
||||
Command string `bson:"command" json:"command,omitempty"` // 执行的命令,包括参数
|
||||
Output string `bson:"output" json:"output,omitempty"` // 任务输出的所有内容
|
||||
Success bool `bson:"success" json:"success"` // 是否执行成功
|
||||
|
@ -98,6 +99,7 @@ func CreateJobLog(j *Job, t time.Time, rs string, success bool) {
|
|||
|
||||
Node: j.runOn,
|
||||
Hostname: j.hostname,
|
||||
IP: j.ip,
|
||||
|
||||
Command: j.Command,
|
||||
Output: rs,
|
||||
|
@ -126,7 +128,7 @@ func CreateJobLog(j *Job, t time.Time, rs string, success bool) {
|
|||
JobLog: jl,
|
||||
}
|
||||
latestLog.Id = ""
|
||||
if err := mgoDB.Upsert(Coll_JobLatestLog, bson.M{"node": jl.Node, "hostname": jl.Hostname, "jobId": jl.JobId, "jobGroup": jl.JobGroup}, latestLog); err != nil {
|
||||
if err := mgoDB.Upsert(Coll_JobLatestLog, bson.M{"node": jl.Node, "hostname": jl.Hostname, "ip": jl.IP, "jobId": jl.JobId, "jobGroup": jl.JobGroup}, latestLog); err != nil {
|
||||
log.Errorf(err.Error())
|
||||
}
|
||||
|
||||
|
|
|
@ -149,7 +149,7 @@ func (n *Node) loadJobs() (err error) {
|
|||
}
|
||||
|
||||
for _, job := range jobs {
|
||||
job.Init(n.ID, n.Hostname)
|
||||
job.Init(n.ID, n.Hostname, n.IP)
|
||||
n.addJob(job, false)
|
||||
}
|
||||
|
||||
|
@ -338,7 +338,7 @@ func (n *Node) groupAddNode(g *cronsun.Group) {
|
|||
continue
|
||||
}
|
||||
|
||||
job.Init(n.ID, n.Hostname)
|
||||
job.Init(n.ID, n.Hostname, n.IP)
|
||||
}
|
||||
|
||||
cmds := job.Cmds(n.ID, n.groups)
|
||||
|
@ -394,7 +394,7 @@ func (n *Node) watchJobs() {
|
|||
continue
|
||||
}
|
||||
|
||||
job.Init(n.ID, n.Hostname)
|
||||
job.Init(n.ID, n.Hostname, n.IP)
|
||||
n.addJob(job, true)
|
||||
case ev.IsModify():
|
||||
job, err := cronsun.GetJobFromKv(ev.Kv.Key, ev.Kv.Value)
|
||||
|
@ -403,7 +403,7 @@ func (n *Node) watchJobs() {
|
|||
continue
|
||||
}
|
||||
|
||||
job.Init(n.ID, n.Hostname)
|
||||
job.Init(n.ID, n.Hostname, n.IP)
|
||||
n.modJob(job)
|
||||
case ev.Type == client.EventTypeDelete:
|
||||
n.delJob(cronsun.GetIDFromKey(string(ev.Kv.Key)))
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"runtime"
|
||||
)
|
||||
|
||||
const VersionNumber = "0.3.0"
|
||||
const VersionNumber = "0.3.1"
|
||||
|
||||
var (
|
||||
Version = fmt.Sprintf("v%s (build %s)", VersionNumber, runtime.Version())
|
||||
|
|
|
@ -15,9 +15,17 @@ import (
|
|||
|
||||
func EnsureJobLogIndex() {
|
||||
cronsun.GetDb().WithC(cronsun.Coll_JobLog, func(c *mgo.Collection) error {
|
||||
return c.EnsureIndex(mgo.Index{
|
||||
c.EnsureIndex(mgo.Index{
|
||||
Key: []string{"beginTime"},
|
||||
})
|
||||
c.EnsureIndex(mgo.Index{
|
||||
Key: []string{"hostname"},
|
||||
})
|
||||
c.EnsureIndex(mgo.Index{
|
||||
Key: []string{"ip"},
|
||||
})
|
||||
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -50,8 +58,21 @@ func (jl *JobLog) GetDetail(ctx *Context) {
|
|||
outJSON(ctx.W, logDetail)
|
||||
}
|
||||
|
||||
func searchText(field string, keywords []string) (q []bson.M) {
|
||||
for _, k := range keywords {
|
||||
k = strings.TrimSpace(k)
|
||||
if len(k) == 0 {
|
||||
continue
|
||||
}
|
||||
q = append(q, bson.M{field: bson.M{"$regex": bson.RegEx{Pattern: k, Options: "i"}}})
|
||||
}
|
||||
|
||||
return q
|
||||
}
|
||||
|
||||
func (jl *JobLog) GetList(ctx *Context) {
|
||||
hostnames := getStringArrayFromQuery("hostnames", ",", ctx.R)
|
||||
ips := getStringArrayFromQuery("ips", ",", ctx.R)
|
||||
names := getStringArrayFromQuery("names", ",", ctx.R)
|
||||
ids := getStringArrayFromQuery("ids", ",", ctx.R)
|
||||
begin := getTime(ctx.R.FormValue("begin"))
|
||||
|
@ -62,26 +83,18 @@ func (jl *JobLog) GetList(ctx *Context) {
|
|||
orderBy := "-beginTime"
|
||||
|
||||
query := bson.M{}
|
||||
if len(hostnames) > 0 {
|
||||
query["hostname"] = bson.M{"$in": hostnames}
|
||||
var textSearch = make([]bson.M, 0, 2)
|
||||
textSearch = append(textSearch, searchText("hostname", hostnames)...)
|
||||
textSearch = append(textSearch, searchText("name", names)...)
|
||||
|
||||
if len(ips) > 0 {
|
||||
query["ip"] = bson.M{"$in": ips}
|
||||
}
|
||||
|
||||
if len(ids) > 0 {
|
||||
query["jobId"] = bson.M{"$in": ids}
|
||||
}
|
||||
|
||||
if len(names) > 0 {
|
||||
var search []bson.M
|
||||
for _, k := range names {
|
||||
k = strings.TrimSpace(k)
|
||||
if len(k) == 0 {
|
||||
continue
|
||||
}
|
||||
search = append(search, bson.M{"name": bson.M{"$regex": bson.RegEx{Pattern: k, Options: "i"}}})
|
||||
}
|
||||
query["$or"] = search
|
||||
}
|
||||
|
||||
if !begin.IsZero() {
|
||||
query["beginTime"] = bson.M{"$gte": begin}
|
||||
}
|
||||
|
@ -93,6 +106,10 @@ func (jl *JobLog) GetList(ctx *Context) {
|
|||
query["success"] = false
|
||||
}
|
||||
|
||||
if len(textSearch) > 0 {
|
||||
query["$or"] = textSearch
|
||||
}
|
||||
|
||||
var pager struct {
|
||||
Total int `json:"total"`
|
||||
List []*cronsun.JobLog `json:"list"`
|
||||
|
|
File diff suppressed because one or more lines are too long
|
@ -61,7 +61,7 @@
|
|||
<div id="app">
|
||||
<div id="initloader"></div>
|
||||
</div>
|
||||
<script src="build.js?v=36c2198"></script>
|
||||
<script src="build.js?v=75b49bd"></script>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
|
|
@ -1,3 +1,11 @@
|
|||
<style scoped>
|
||||
.ui.vertical.menu h4 {
|
||||
background: rgba(0,0,0,.05);
|
||||
margin-bottom: 0px;
|
||||
margin-top: 0px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<template>
|
||||
<div id="app">
|
||||
<div class="ui blue inverted menu fixed">
|
||||
|
@ -7,25 +15,35 @@
|
|||
<router-link v-if="shouldOpen" class="item" to="/job" v-bind:class="{active: this.$route.path.indexOf('/job') === 0}"><i class="calendar icon"></i> {{$L('job')}}</router-link>
|
||||
<router-link v-if="shouldOpen" class="item" to="/node" v-bind:class="{active: this.$route.path.indexOf('/node') === 0}"><i class="server icon"></i> {{$L('node')}}</router-link>
|
||||
<router-link v-if="$store.getters.enabledAuth && $store.getters.role === 1" class="item" to="/admin/account/list" v-bind:class="{active: this.$route.path.indexOf('/admin/account') === 0}"><i class="user icon"></i> {{$L('account')}}</router-link>
|
||||
|
||||
<a class="item" href="https://github.com/shunfei/cronsun/wiki" target="_blank"><i class="external alternate icon"></i> Docs</a>
|
||||
<div class="right menu">
|
||||
<router-link to="/user/setpwd" class="item" v-if="this.$store.getters.email"><i class="user icon"></i> {{this.$store.getters.email}}</router-link>
|
||||
<a class="item" v-if="this.$store.getters.email" href="#" v-on:click="logout"><i class="sign out icon"></i></a>
|
||||
|
||||
<div ref="langSelection" class="ui right icon dropdown item">
|
||||
<i class="world icon" style="margin-left:-1px; margin-right: 8px;"></i>
|
||||
<span class="text">Language</span>
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<div class="item" v-for="lang in $Lang.supported" :data-value="lang.code">{{lang.name}}</div>
|
||||
</div>
|
||||
</div>
|
||||
<a class="item" href="#" @click.prevent="toggleSetting"><i class="settings icon"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div style="height: 55px;"></div>
|
||||
<div class="ui container">
|
||||
<div class="ui container pusher">
|
||||
<router-view></router-view>
|
||||
</div>
|
||||
|
||||
<div ref="sidebar" class="ui sidebar right vertical menu">
|
||||
<h4 class="item">{{$store.getters.version}}</h4>
|
||||
<h4 class="item">Language</h4>
|
||||
<div class="item">
|
||||
<div class="menu">
|
||||
<a class="item" :class="{active: locale === lang.code}" href="#" v-for="lang in $Lang.supported" @click.prevent="selectLanguage(lang.code)">{{lang.name}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<h4 class="item">{{$L('node show as')}}</h4>
|
||||
<div class="item">
|
||||
<div class="menu">
|
||||
<a class="item" :class="{active: hostshow === h.value}" href="#" v-for="h in hostshowsList" @click.prevent="selectHostshows(h.value)">{{h.name}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Messager/>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -39,21 +57,25 @@ export default {
|
|||
name: 'app',
|
||||
store,
|
||||
|
||||
mounted: function(){
|
||||
$(this.$refs.langSelection).dropdown({
|
||||
onChange: function(value, text){
|
||||
var old = window.$.cookie('locale');
|
||||
if (old !== value) {
|
||||
window.$.cookie('locale', value)
|
||||
window.location.reload()
|
||||
}
|
||||
}
|
||||
});
|
||||
data: function() {
|
||||
return {
|
||||
hostshowsList: [{name: this.$L('hostname'), value: 'hostname'}, {name: 'IP', value: 'ip'}],
|
||||
locale: ''
|
||||
}
|
||||
},
|
||||
|
||||
created: function() {
|
||||
this.locale = window.$.cookie('locale');
|
||||
this.$store.commit('setShowWithHostname', window.$.cookie('hostshows') === 'hostname');
|
||||
},
|
||||
|
||||
computed: {
|
||||
shouldOpen() {
|
||||
return !this.$store.getters.enabledAuth || (this.$store.getters.enabledAuth && this.$store.getters.email)
|
||||
},
|
||||
|
||||
hostshow() {
|
||||
return this.$store.getters.showWithHostname ? 'hostname' : 'ip';
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -67,6 +89,28 @@ export default {
|
|||
vm.$router.push('/login');
|
||||
}).
|
||||
do();
|
||||
},
|
||||
|
||||
toggleSetting() {
|
||||
$(this.$refs.sidebar).sidebar('toggle');
|
||||
},
|
||||
|
||||
selectLanguage(code) {
|
||||
if (this.locale !== code) {
|
||||
window.$.cookie('locale', code);
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
this.toggleSetting();
|
||||
},
|
||||
|
||||
selectHostshows(v) {
|
||||
if (this.hostshow !== v) {
|
||||
window.$.cookie('hostshows', v);
|
||||
window.location.reload();
|
||||
return;
|
||||
}
|
||||
this.toggleSetting();
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
@ -27,8 +27,6 @@ export default {
|
|||
loading: false
|
||||
}
|
||||
},
|
||||
|
||||
mounted(){},
|
||||
|
||||
methods: {
|
||||
show(jobName, jobGroup, jobId){
|
||||
|
@ -53,7 +51,7 @@ export default {
|
|||
onsucceed(200, (resp)=>{
|
||||
var nodes = [{value: 'all nodes', name: vm.$L('all nodes')}];
|
||||
for (var i in resp) {
|
||||
nodes.push({value: resp[i], name: vm.$store.getters.getHostnameByID(resp[i])})
|
||||
nodes.push({value: resp[i], name: vm.$store.getters.hostshows(resp[i])})
|
||||
}
|
||||
vm.nodes = nodes;
|
||||
}).
|
||||
|
|
|
@ -183,7 +183,7 @@ export default {
|
|||
},
|
||||
|
||||
formatLatest: function(latest){
|
||||
return this.$L('on {node} took {times}, {begin ~ end}', latest.hostname, formatDuration(latest.beginTime, latest.endTime), formatTime(latest.beginTime, latest.endTime));
|
||||
return this.$L('on {node} took {times}, {begin ~ end}', this.$store.getters.hostshowsWithoutTip(latest.node), formatDuration(latest.beginTime, latest.endTime), formatTime(latest.beginTime, latest.endTime));
|
||||
},
|
||||
|
||||
showExecuteJobModal: function(jobName, jobGroup, jobId){
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
</div>
|
||||
<div class="field">
|
||||
<label>{{$L('select nodes')}}</label>
|
||||
<Dropdown :title="$L('select nodes')" v-bind:items="prefetchs.nodes" v-on:change="changeNodes" :selected="nodes" :multiple="true"/>
|
||||
<Dropdown :title="$L('select nodes')" v-bind:items="$store.getters.dropdownNodes" v-on:change="changeNodes" :selected="nodes" :multiple="true"/>
|
||||
</div>
|
||||
<div class="field">
|
||||
<button class="fluid ui button" type="button" v-on:click="submit">{{$L('submit query')}}</button>
|
||||
|
@ -39,7 +39,7 @@
|
|||
<tr v-for="(proc, index) in executings">
|
||||
<td class="center aligned"><router-link :to="'/job/edit/'+proc.group+'/'+proc.jobId">{{proc.jobId}}</router-link></td>
|
||||
<td class="center aligned">{{proc.group}}</td>
|
||||
<td class="center aligned">{{$store.getters.getHostnameByID(proc.nodeId)}}</td>
|
||||
<td class="center aligned">{{$store.getters.hostshows(proc.nodeId)}}</td>
|
||||
<td class="center aligned">{{proc.id}}</td>
|
||||
<td class="center aligned">{{proc.time}}</td>
|
||||
</tr>
|
||||
|
@ -56,7 +56,7 @@ export default {
|
|||
name: 'job-executing',
|
||||
data(){
|
||||
return {
|
||||
prefetchs: {groups: [], nodes: []},
|
||||
prefetchs: {groups: []},
|
||||
loading: false,
|
||||
groups: [],
|
||||
ids: '',
|
||||
|
@ -76,12 +76,6 @@ export default {
|
|||
vm.prefetchs.groups = resp;
|
||||
this.fetchList(this.buildQuery());
|
||||
}).do();
|
||||
|
||||
this.$rest.GET('nodes').onsucceed(200, (resp)=>{
|
||||
for (var i in resp) {
|
||||
vm.prefetchs.nodes.push(resp[i].id);
|
||||
}
|
||||
}).do();
|
||||
},
|
||||
|
||||
watch: {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div>
|
||||
<form class="ui form" method="GET" v-bind:class="{loading:loading}" v-on:submit.prevent>
|
||||
<form class="ui form" method="GET" v-bind:class="{loading:loading}" v-on:submit.prevent v-on:keyup.enter="submit">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<label>{{$L('job name')}}</label>
|
||||
|
@ -8,12 +8,13 @@
|
|||
</div>
|
||||
<div class="field">
|
||||
<label>{{$L('job ID')}}</label>
|
||||
<input type="text" v-model="ids" :placeholder="$L('multiple IDs can separated by commas')">
|
||||
<input type="text" v-model="ids" :placeholder="$L('multiple IDs can separated by commas')">
|
||||
</div>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label>{{$L('node')}}</label>
|
||||
<input type="text" v-model="hostnames" :placeholder="$L('multiple Hostnames can separated by commas')">
|
||||
<input v-if="$store.getters.showWithHostname" type="text" v-model="hostnames" :placeholder="$L('multiple Hostnames can separated by commas')">
|
||||
<input v-else type="text" v-model="ips" :placeholder="$L('multiple IPs can separated by commas')">
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
|
@ -56,7 +57,7 @@
|
|||
<tbody>
|
||||
<tr v-for="log in list">
|
||||
<td><router-link class="item" :to="'/job/edit/'+log.jobGroup+'/'+log.jobId">{{log.name}}</router-link></td>
|
||||
<td :title="log.node">{{$store.getters.getHostnameByID(log.node)}}</td>
|
||||
<td :title="log.node">{{$store.getters.hostshows(log.node)}}</td>
|
||||
<td>{{log.user}}</td>
|
||||
<td :class="{warning: durationAttention(log.beginTime, log.endTime)}"><i class="attention icon" v-if="durationAttention(log.beginTime, log.endTime)"></i> {{formatTime(log)}}</td>
|
||||
<td :class="{error: !log.success}">
|
||||
|
@ -84,6 +85,7 @@ export default {
|
|||
names: '',
|
||||
ids: '',
|
||||
hostnames: '',
|
||||
ips: '',
|
||||
begin: '',
|
||||
end: '',
|
||||
latest: false,
|
||||
|
@ -115,6 +117,7 @@ export default {
|
|||
this.names = this.$route.query.names || '';
|
||||
this.ids = this.$route.query.ids || '';
|
||||
this.hostnames = this.$route.query.hostnames || '';
|
||||
this.ips = this.$route.query.ips || '';
|
||||
this.begin = this.$route.query.begin || '';
|
||||
this.end = this.$route.query.end || '';
|
||||
this.page = this.$route.query.page || 1;
|
||||
|
@ -138,8 +141,9 @@ export default {
|
|||
buildQuery(){
|
||||
var params = [];
|
||||
if (this.names) params.push('names='+this.names);
|
||||
if (this.ids) params.push('ids='+this.ids);
|
||||
if (this.hostnames) params.push('hostnames='+this.hostnames);
|
||||
if (!this.$store.getters.showWithHostname && this.ids) params.push('ids='+this.ids);
|
||||
if (this.$store.getters.showWithHostname && this.hostnames) params.push('hostnames='+this.hostnames);
|
||||
if (this.ips) params.push('ips='+this.ips);
|
||||
if (this.begin) params.push('begin='+this.begin);
|
||||
if (this.end) params.push('end='+this.end);
|
||||
if (this.failedOnly) params.push('failedOnly=true');
|
||||
|
|
|
@ -34,14 +34,14 @@
|
|||
<i class="cube icon" v-bind:class="group.css"></i> {{group.nodes.length}} {{$L(group.name)}}
|
||||
</div>
|
||||
{{$L('(total {n} nodes)', count)}}
|
||||
<div class="ui label" :title="$L('currently version')"> {{version}} </div>
|
||||
<div class="ui label" :title="$L('currently version')"> {{version}}</div>
|
||||
</div>
|
||||
<div class="ui relaxed list" v-for="(group, groupIndex) in groups">
|
||||
<h4 v-if="group.nodes.length > 0" class="ui horizontal divider header"><i class="cube icon" v-bind:class="group.css"></i> {{$L(group.name)}} {{group.nodes.length}}</h4>
|
||||
<div v-for="(node, nodeIndex) in group.nodes" class="node" v-bind:title="node.title">
|
||||
<router-link class="item" :to="'/job?node='+node.id">
|
||||
<i class="red icon fork" v-if="node.version !== version" :title="$L('version inconsistent, node: {version}', node.version)"></i>
|
||||
{{node.hostname || node.id+"(need to upgrade)"}}
|
||||
{{$store.getters.hostshows(node.id)}}
|
||||
</router-link>
|
||||
<i v-if="groupIndex != 2" v-on:click="removeConfirm(groupIndex, nodeIndex, node.id)" class="icon remove"></i>
|
||||
</div>
|
||||
|
@ -59,16 +59,12 @@ export default {
|
|||
{nodes: [], name: 'node offline', title: 'node is in maintenance or is shutdown manually', css:''},
|
||||
{nodes: [], name: 'node normaly', title: 'node is running', css:'green'}
|
||||
],
|
||||
count: 0,
|
||||
version: ''
|
||||
count: 0
|
||||
}
|
||||
},
|
||||
|
||||
mounted: function(){
|
||||
var vm = this;
|
||||
this.$rest.GET('version').onsucceed(200, (resp)=>{
|
||||
vm.version = resp;
|
||||
}).do();
|
||||
|
||||
var nodes = this.$store.getters.nodes;
|
||||
for (var id in nodes) {
|
||||
|
@ -86,6 +82,12 @@ export default {
|
|||
vm.count = Object.keys(nodes).length;
|
||||
},
|
||||
|
||||
computed: {
|
||||
version: function(){
|
||||
return this.$store.getters.version;
|
||||
}
|
||||
},
|
||||
|
||||
methods: {
|
||||
removeConfirm: function(groupIndex, nodeIndex, nodeId){
|
||||
if (!confirm(this.$L('are you sure to remove the node {nodeId}?', nodeId))) return;
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<div class="description">
|
||||
<div class="ui middle large aligned divided list">
|
||||
<div class="item" v-for="nodeID in g.nids">
|
||||
<span v-if="nodes[nodeID]">{{nodes[nodeID].hostname || nodes[nodeID].id}}
|
||||
<span v-if="nodes[nodeID]">{{$store.getters.hostshows(nodeID)}}
|
||||
<i class="arrow circle up icon red" v-if="nodes[nodeID].hostname == ''"></i>
|
||||
<i v-if="nodes[nodeID].hostname == ''">(need to upgrade)</i>
|
||||
</span>
|
||||
|
|
|
@ -24,6 +24,8 @@ var language = {
|
|||
'total number of executeds': 'Total executeds',
|
||||
'total number of nodes': 'Total nodes',
|
||||
'job executed in past 7 days': 'Job executed in past 7 days',
|
||||
'node show as': 'Node show as',
|
||||
'hostname': 'Hostname',
|
||||
|
||||
'batch': 'Batch',
|
||||
'job name': 'Job name',
|
||||
|
@ -31,6 +33,7 @@ var language = {
|
|||
'job ID': 'Job ID',
|
||||
'multiple IDs can separated by commas': 'Multiple IDs can separated by commas',
|
||||
'multiple Hostnames can separated by commas': 'Multiple Hostnames can separated by commas',
|
||||
'multiple IPs can separated by commas': 'Multiple IPs can separated by commas',
|
||||
'starting date': 'Starting date',
|
||||
'end date': 'End date',
|
||||
'failure only': 'Failure only',
|
||||
|
|
|
@ -24,6 +24,8 @@ var language = {
|
|||
'total number of executeds': '执行任务总次数',
|
||||
'total number of nodes': '节点总数',
|
||||
'job executed in past 7 days': '过去 7 天任务统计',
|
||||
'node show as': '节点显示为',
|
||||
'hostname': '主机名称',
|
||||
|
||||
'batch': '批量',
|
||||
'job name': '任务名称',
|
||||
|
@ -31,6 +33,7 @@ var language = {
|
|||
'job ID': '任务 ID',
|
||||
'multiple IDs can separated by commas': '多个 ID 用英文逗号分隔',
|
||||
'multiple Hostnames can separated by commas': '多个主机名称用英文逗号分隔',
|
||||
'multiple IPs can separated by commas': '多个 IP 用英文逗号分隔',
|
||||
'starting date': '起始日期',
|
||||
'end date': '截至日期',
|
||||
'failure only': '只看失败的任务',
|
||||
|
|
|
@ -123,6 +123,10 @@ var initConf = new Promise((resolve) => {
|
|||
store.commit('enabledAuth', resp.enabledAuth);
|
||||
store.commit('setEmail', resp.email);
|
||||
store.commit('setRole', resp.role);
|
||||
|
||||
restApi.GET('version').onsucceed(200, (resp)=>{
|
||||
store.commit('setVersion', resp);
|
||||
}).do();
|
||||
|
||||
restApi.GET('configurations').
|
||||
onsucceed(200, (resp) => {
|
||||
|
|
|
@ -5,16 +5,21 @@ Vue.use(Vuex);
|
|||
|
||||
const store = new Vuex.Store({
|
||||
state: {
|
||||
version: '',
|
||||
enabledAuth: false,
|
||||
user: {
|
||||
email: '',
|
||||
role: 0
|
||||
},
|
||||
nodes: {},
|
||||
dropdownNodes: []
|
||||
showWithHostname: false
|
||||
},
|
||||
|
||||
getters: {
|
||||
version: function (state) {
|
||||
return state.version;
|
||||
},
|
||||
|
||||
email: function (state) {
|
||||
return state.user.email;
|
||||
},
|
||||
|
@ -31,11 +36,16 @@ const store = new Vuex.Store({
|
|||
return state.nodes;
|
||||
},
|
||||
|
||||
getHostnameByID: function (state) {
|
||||
return (id) => {
|
||||
if (!state.nodes[id]) return id + '(node not found)';
|
||||
return state.nodes[id].hostname || id + '(need to upgrade)';
|
||||
}
|
||||
showWithHostname: function (state) {
|
||||
return state.showWithHostname;
|
||||
},
|
||||
|
||||
hostshows: function (state) {
|
||||
return (id) => _hostshows(id, state, true);
|
||||
},
|
||||
|
||||
hostshowsWithoutTip: function (state) {
|
||||
return (id) => _hostshows(id, state, false);
|
||||
},
|
||||
|
||||
getNodeByID: function (state) {
|
||||
|
@ -45,11 +55,23 @@ const store = new Vuex.Store({
|
|||
},
|
||||
|
||||
dropdownNodes: function (state) {
|
||||
return state.dropdownNodes;
|
||||
var dn = [];
|
||||
var nodes = state.nodes;
|
||||
for (var i in nodes) {
|
||||
dn.push({
|
||||
value: nodes[i].id,
|
||||
name: _hostshows(nodes[i].id, state, true)
|
||||
});
|
||||
}
|
||||
return dn;
|
||||
}
|
||||
},
|
||||
|
||||
mutations: {
|
||||
setVersion: function (state, v) {
|
||||
state.version = v;
|
||||
},
|
||||
|
||||
setEmail: function (state, email) {
|
||||
state.user.email = email;
|
||||
},
|
||||
|
@ -64,13 +86,26 @@ const store = new Vuex.Store({
|
|||
|
||||
setNodes: function (state, nodes) {
|
||||
state.nodes = nodes;
|
||||
var dn = []
|
||||
for (var i in nodes) {
|
||||
dn.push({value: nodes[i].id, name: nodes[i].hostname || nodes[i].id + '(need to upgrade)'})
|
||||
}
|
||||
state.dropdownNodes = dn;
|
||||
},
|
||||
|
||||
setShowWithHostname: function (state, b) {
|
||||
state.showWithHostname = b;
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
function _hostshows(id, state, tip) {
|
||||
if (!state.nodes[id]) {
|
||||
if (tip) id += '(node not found)';
|
||||
return id;
|
||||
}
|
||||
|
||||
var show = state.showWithHostname ? state.nodes[id].hostname : state.nodes[id].ip;
|
||||
if (!show) {
|
||||
show = id
|
||||
if (tip) show += '(need to upgrade)';
|
||||
}
|
||||
return show;
|
||||
}
|
||||
|
||||
export default store
|
||||
|
|
Loading…
Reference in New Issue