Initial commit (code only without large binaries)
This commit is contained in:
4
EdgeAdmin/web/views/@default/ns/clusters/@menu.html
Normal file
4
EdgeAdmin/web/views/@default/ns/clusters/@menu.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<first-menu>
|
||||
<menu-item href="/ns/clusters" code="index">集群列表</menu-item>
|
||||
<menu-item href="/ns/clusters/create" code="create">创建集群</menu-item>
|
||||
</first-menu>
|
||||
@@ -0,0 +1,5 @@
|
||||
.access-log-row em {
|
||||
font-style: italic !important;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,eACC;EACC,6BAAA;EACA,yBAAA","file":"index.css"}
|
||||
@@ -0,0 +1,69 @@
|
||||
{$layout}
|
||||
{$template "/datepicker"}
|
||||
|
||||
<div class="margin"></div>
|
||||
<form method="get" class="ui form small" :action="path" autocomplete="off">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<ns-cluster-combo-box :v-cluster-id="clusterId"></ns-cluster-combo-box>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="recordType" v-model="recordType">
|
||||
<option value="">[记录类型]</option>
|
||||
<option v-for="r in recordTypes" :value="r.type">{{r.type}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" v-model="keyword" placeholder="IP、域名、记录等..."/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="day" maxlength="10" placeholder="选择日期" style="width:7.8em" id="day-input" v-model="day"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button small" type="submit">查找</button>
|
||||
|
||||
<a :href="'/ns/clusters/accessLogs?day=' + day" v-if="clusterId > 0 || keyword.length > 0 || recordType.length > 0">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<not-found-box v-if="accessLogs.length == 0">暂时还没有访问日志。</not-found-box>
|
||||
|
||||
<table class="ui table selectable celled" v-if="accessLogs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="two wide">集群</th>
|
||||
<th class="two wide">节点</th>
|
||||
<th class="two wide">域名</th>
|
||||
<th style="width: 6em">类型</th>
|
||||
<th>概要</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="accessLog in accessLogs" :key="accessLog.requestId">
|
||||
<td>
|
||||
<div v-if="accessLog.node.cluster != null">
|
||||
<link-icon :href="'/ns/clusters/cluster?clusterId=' + accessLog.node.cluster.id">{{accessLog.node.cluster.name}}</link-icon>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="accessLog.node != null">
|
||||
<link-icon :href="'/ns/clusters/cluster/node?clusterId=' + accessLog.node.cluster.id + '&nodeId=' + accessLog.node.id">{{accessLog.node.name}}</link-icon>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<div v-if="accessLog.domain != null">
|
||||
<link-icon :href="'/ns/domains/domain?domainId=' + accessLog.domain.id">{{accessLog.domain.name}}</link-icon>
|
||||
</div>
|
||||
</td>
|
||||
<td>{{accessLog.questionType}}</td>
|
||||
<td><ns-access-log-box :v-access-log="accessLog" :v-keyword="keyword"></ns-access-log-box></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-if="accessLogs.length > 0">
|
||||
<a :href="path + '?requestId=' + lastRequestId + '&day=' + day + '&keyword=' + keyword + '&recordType=' + recordType + '&clusterId=' + clusterId" v-if="hasPrev">上一页</a>
|
||||
<span v-else class="disabled">上一页</span>
|
||||
<span class="disabled"> | </span>
|
||||
<a :href="path + '?requestId=' + nextRequestId + '&day=' + day + '&keyword=' + keyword + '&recordType=' + recordType + '&clusterId=' + clusterId" v-if="hasMore">下一页</a>
|
||||
<span v-else class="disabled">下一页</span>
|
||||
</div>
|
||||
32
EdgeAdmin/web/views/@default/ns/clusters/accessLogs/index.js
Normal file
32
EdgeAdmin/web/views/@default/ns/clusters/accessLogs/index.js
Normal file
@@ -0,0 +1,32 @@
|
||||
Tea.context(function () {
|
||||
let that = this
|
||||
this.accessLogs.forEach(function (accessLog) {
|
||||
// 区域
|
||||
if (typeof (that.regions[accessLog.remoteAddr]) == "string") {
|
||||
accessLog.region = that.regions[accessLog.remoteAddr]
|
||||
} else {
|
||||
accessLog.region = ""
|
||||
}
|
||||
|
||||
// 节点
|
||||
if (typeof (that.nodes[accessLog.nsNodeId]) != "undefined") {
|
||||
accessLog["node"] = that.nodes[accessLog.nsNodeId]
|
||||
} else {
|
||||
accessLog["node"] = null
|
||||
}
|
||||
|
||||
// 域名
|
||||
if (typeof (that.domains[accessLog.nsDomainId]) != "undefined") {
|
||||
accessLog["domain"] = that.domains[accessLog.nsDomainId]
|
||||
} else {
|
||||
accessLog["domain"] = null
|
||||
}
|
||||
})
|
||||
|
||||
this.$delay(function () {
|
||||
let that = this
|
||||
teaweb.datepicker("day-input", function (v) {
|
||||
that.day = v
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,6 @@
|
||||
.access-log-row {
|
||||
em {
|
||||
font-style: italic !important;
|
||||
font-size: 1em !important;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<second-menu>
|
||||
<menu-item :href="'/ns/clusters/cluster?clusterId=' + currentCluster.id">{{currentCluster.name}}</menu-item>
|
||||
<span class="item disabled" style="padding-left: 0; padding-right: 0">»</span>
|
||||
<menu-item :href="'/ns/clusters/cluster?clusterId=' + clusterId" code="index">节点列表</menu-item>
|
||||
<menu-item :href="'/ns/clusters/cluster/createNode?clusterId=' + clusterId" code="create">创建节点</menu-item>
|
||||
<!--<menu-item :href="'/ns/clusters/cluster/installManual?clusterId=' + clusterId" code="install">安装升级</menu-item>
|
||||
<menu-item :href="'/ns/clusters/cluster/groups?clusterId=' + clusterId" code="group">节点分组</menu-item>-->
|
||||
</second-menu>
|
||||
@@ -0,0 +1,7 @@
|
||||
.left-box {
|
||||
top: 10em;
|
||||
}
|
||||
.right-box {
|
||||
top: 10em;
|
||||
}
|
||||
/*# sourceMappingURL=createNode.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["createNode.less"],"names":[],"mappings":"AAAA;EACC,SAAA;;AAGD;EACC,SAAA","file":"createNode.css"}
|
||||
@@ -0,0 +1,22 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">节点名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP地址 *</td>
|
||||
<td>
|
||||
<node-ip-addresses-box role="ns"></node-ip-addresses-box>
|
||||
<p class="comment">用于访问节点和域名解析等。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifySuccess("保存成功", "/ns/clusters/cluster?clusterId=" + this.clusterId);
|
||||
});
|
||||
@@ -0,0 +1,7 @@
|
||||
.left-box {
|
||||
top: 10em;
|
||||
}
|
||||
|
||||
.right-box {
|
||||
top: 10em;
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
.buttons-box {
|
||||
text-align: center;
|
||||
margin-top: 2em;
|
||||
}
|
||||
.buttons-box button {
|
||||
width: 20em;
|
||||
}
|
||||
/*# sourceMappingURL=delete.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["delete.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;EACA,eAAA;;AAFD,YAIC;EACC,WAAA","file":"delete.css"}
|
||||
@@ -0,0 +1,6 @@
|
||||
{$layout}
|
||||
|
||||
<div class="buttons-box">
|
||||
<button class="ui button red" type="button" @click.prevent="deleteCluster(clusterId)">删除当前集群</button>
|
||||
<p class="comment">包含{{countDomains}}域名</p>
|
||||
</div>
|
||||
22
EdgeAdmin/web/views/@default/ns/clusters/cluster/delete.js
Normal file
22
EdgeAdmin/web/views/@default/ns/clusters/cluster/delete.js
Normal file
@@ -0,0 +1,22 @@
|
||||
Tea.context(function () {
|
||||
this.deleteCluster = function (clusterId) {
|
||||
let that = this
|
||||
|
||||
let message = "确定要删除此集群吗?"
|
||||
if (this.countDomains > 0) {
|
||||
message = "当前集群上部署了" + this.countDomains + "个域名,确定要删除此集群吗?"
|
||||
}
|
||||
|
||||
teaweb.confirm(message, function () {
|
||||
that.$post("/ns/clusters/cluster/delete")
|
||||
.params({
|
||||
clusterId: clusterId
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("删除成功", function () {
|
||||
window.location = "/ns/clusters"
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,8 @@
|
||||
.buttons-box {
|
||||
text-align: center;
|
||||
margin-top: 2em;
|
||||
|
||||
button {
|
||||
width: 20em;
|
||||
}
|
||||
}
|
||||
23
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.css
Normal file
23
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.css
Normal file
@@ -0,0 +1,23 @@
|
||||
.table th.value-column {
|
||||
width: 7em;
|
||||
}
|
||||
.node-name-td {
|
||||
position: relative;
|
||||
}
|
||||
.node-name-td .icon.setting {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 50%;
|
||||
margin-top: -1em;
|
||||
}
|
||||
.node-name-td:hover .icon.setting {
|
||||
display: inline;
|
||||
}
|
||||
.label a {
|
||||
opacity: 1 !important;
|
||||
}
|
||||
.label a span {
|
||||
border-bottom: 1px #db2828 dashed;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,MACC,GAAE;EACD,UAAA;;AAIF;EACC,kBAAA;;AADD,aAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,gBAAA;;AAIF,aAAa,MACZ,MAAK;EACJ,eAAA;;AAIF,MAAO;EACN,qBAAA;;AADD,MAAO,EAGN;EACC,iCAAA","file":"index.css"}
|
||||
115
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.html
Normal file
115
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.html
Normal file
@@ -0,0 +1,115 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<form class="ui form" action="/ns/clusters/cluster" v-show="countAll > 0">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="installedState" v-model="installState">
|
||||
<option value="0">[安装状态]</option>
|
||||
<option value="1">已安装</option>
|
||||
<option value="2">未安装</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="activeState" v-model="activeState">
|
||||
<option value="0">[在线状态]</option>
|
||||
<option value="1">在线</option>
|
||||
<option value="2">不在线</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" placeholder="关键词" v-model="keyword" style="width:10em"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button class="ui button" type="submit">搜索</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div v-if="countAll == 0">
|
||||
<not-found-box message="当前集群下还没有节点,至少添加一个节点后才能提供服务。">
|
||||
<div style="margin-top: 0.5em">
|
||||
<a :href="'/ns/clusters/cluster/createNode?clusterId=' + clusterId">[创建节点]</a>
|
||||
</div>
|
||||
</not-found-box>
|
||||
</div>
|
||||
<div v-if="countAll > 0">
|
||||
<p class="comment" v-if="nodes.length == 0">暂时还没有节点。</p>
|
||||
</div>
|
||||
|
||||
<table class="ui table selectable celled" v-if="nodes.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>节点名称</th>
|
||||
<th class="four wide">IP</th>
|
||||
<th class="value-column center" v-if="windowWidth < miniWidth || windowWidth > columnWidth1">CPU</th>
|
||||
<th class="value-column center" v-if="windowWidth < miniWidth || windowWidth > columnWidth2">内存</th>
|
||||
<th class="value-column center" v-if="windowWidth < miniWidth || windowWidth > columnWidth3">负载</th>
|
||||
<th class="two wide center">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="node in nodes">
|
||||
<td class="node-name-td"><a :href="'/ns/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id"><keyword :v-word="keyword">{{node.name}}</keyword></a>
|
||||
<div v-if="node.status != null && node.status.version.length > 0 && node.status.version != latestVersion">
|
||||
<span class="small red">v{{node.status.version}} -> v{{latestVersion}}</span>
|
||||
</div>
|
||||
|
||||
<a :href="'/ns/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" title="设置"><i class="icon setting grey"></i></a>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="node.ipAddresses.length == 0" class="disabled">-</span>
|
||||
<div v-else class="address-box">
|
||||
<div v-for="addr in node.ipAddresses" style="margin-bottom:0.3em">
|
||||
<div class="ui label tiny basic">{{addr.ip}}
|
||||
<span class="small" v-if="addr.name.length > 0">({{addr.name}}<span v-if="!addr.canAccess">,不公开访问</span>)</span>
|
||||
<span class="small" v-if="addr.name.length == 0 && !addr.canAccess">(不公开访问)</span>
|
||||
<span v-if="addr.hasError"> <a href="" @click.prevent="showPortError(addr)"><span class="small red">异常</span></a></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth1">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.cpuUsage > 0.80}">{{node.status.cpuUsageText}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth2">
|
||||
<span v-if="node.status.isActive" :class="{red:node.status.memUsage > 0.80}">{{node.status.memUsageText}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center" v-if="windowWidth < miniWidth || windowWidth > columnWidth3">
|
||||
<span v-if="node.status.isActive && node.status.load1m > 0">{{node.status.load1m}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<div v-if="!node.isUp">
|
||||
<span class="red">健康问题下线</span>
|
||||
<div>
|
||||
<a href="" @click.prevent="upNode(node.id)">[上线]</a>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="!node.isOn">
|
||||
<label-on :v-is-on="node.isOn"></label-on>
|
||||
</div>
|
||||
<div v-else-if="node.isInstalled">
|
||||
<div v-if="node.status.isActive">
|
||||
<span class="green">运行中</span>
|
||||
</div>
|
||||
<span v-else-if="node.status.updatedAt > 0" class="red">已断开</span>
|
||||
<span v-else-if="node.status.updatedAt == 0" class="red">未连接</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span v-if="node.installStatus.isRunning" class="red">安装中</span>
|
||||
<a v-if="node.installStatus.isFinished && !node.installStatus.isOk" :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" title="点击看安装错误"><span class="red">安装出错</span></a>
|
||||
<a v-else class="red" :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" title="点击进安装界面"><span class="red">未安装</span></a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/ns/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id">详情</a> <a href="" @click.prevent="deleteNode(node.id)">删除</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
98
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.js
Normal file
98
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.js
Normal file
@@ -0,0 +1,98 @@
|
||||
Tea.context(function () {
|
||||
// 显示的统计项
|
||||
this.windowWidth = window.innerWidth
|
||||
this.miniWidth = 760
|
||||
this.columnWidth1 = 750
|
||||
this.columnWidth2 = 850
|
||||
this.columnWidth3 = 950
|
||||
this.columnWidth4 = 1050
|
||||
this.columnWidth5 = 1100
|
||||
|
||||
let that = this
|
||||
window.addEventListener("resize", function () {
|
||||
that.windowWidth = window.innerWidth
|
||||
})
|
||||
|
||||
this.$delay(function () {
|
||||
this.checkPorts()
|
||||
})
|
||||
|
||||
this.deleteNode = function (nodeId) {
|
||||
teaweb.confirm("确定要删除这个节点吗?", function () {
|
||||
this.$post("/ns/clusters/cluster/deleteNode")
|
||||
.params({
|
||||
nodeId: nodeId
|
||||
})
|
||||
.refresh();
|
||||
})
|
||||
}
|
||||
|
||||
this.upNode = function (nodeId) {
|
||||
teaweb.confirm("确定要手动上线此节点吗?", function () {
|
||||
this.$post("/ns/clusters/cluster/node/up")
|
||||
.params({
|
||||
nodeId: nodeId
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
let checkingPort = ""
|
||||
this.checkPorts = function () {
|
||||
let ipList = []
|
||||
this.nodes.forEach(function (node) {
|
||||
if (node.isOn) {
|
||||
if (node.ipAddresses != null && node.ipAddresses.length > 0) {
|
||||
node.ipAddresses.forEach(function (addr) {
|
||||
if (addr.isOn && addr.canAccess && addr.isUp && addr.ip.length > 0 && !ipList.$contains(addr.ip)) {
|
||||
ipList.push(addr.ip)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
if (ipList.length > 0) {
|
||||
this.$post(".checkPorts")
|
||||
.params({
|
||||
clusterId: this.clusterId,
|
||||
ip: ipList
|
||||
})
|
||||
.success(function (resp) {
|
||||
let results = resp.data.results
|
||||
if (results.length > 0) {
|
||||
checkingPort = resp.data.port
|
||||
let errorMap = {}
|
||||
let hasErrors = false
|
||||
results.forEach(function (result) {
|
||||
if (!result.isOk) {
|
||||
errorMap[result.ip] = result
|
||||
hasErrors = true
|
||||
}
|
||||
})
|
||||
|
||||
if (hasErrors) {
|
||||
this.nodes.forEach(function (node) {
|
||||
if (node.isOn) {
|
||||
if (node.ipAddresses != null && node.ipAddresses.length > 0) {
|
||||
node.ipAddresses.forEach(function (addr, index) {
|
||||
if (addr.isOn && addr.canAccess && addr.isUp && addr.ip.length > 0) {
|
||||
if (typeof errorMap[addr.ip] == "object") {
|
||||
addr.hasError = true
|
||||
addr.err = errorMap[addr.ip].err
|
||||
Vue.set(node.ipAddresses, index, addr)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.showPortError = function (addr) {
|
||||
teaweb.popupTip("udp://" + addr.ip + ":" + checkingPort + " 端口连接错误(提示:" + addr.err + "),请检查:<br/>1)节点IP地址是否填写正确;<br/>2)节点程序(edge-dns)是否已正确安装;<br/>3)是否已在防火墙和安全策略中正确设置 " + checkingPort + "/udp 端口;<br/>4)如在客户端手动测试正常,可以忽略此提示。")
|
||||
}
|
||||
})
|
||||
31
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.less
Normal file
31
EdgeAdmin/web/views/@default/ns/clusters/cluster/index.less
Normal file
@@ -0,0 +1,31 @@
|
||||
.table {
|
||||
th.value-column {
|
||||
width: 7em;
|
||||
}
|
||||
}
|
||||
|
||||
.node-name-td {
|
||||
position: relative;
|
||||
|
||||
.icon.setting {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 50%;
|
||||
margin-top: -1em;
|
||||
}
|
||||
}
|
||||
|
||||
.node-name-td:hover {
|
||||
.icon.setting {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
.label a {
|
||||
opacity: 1 !important;
|
||||
|
||||
span {
|
||||
border-bottom: 1px #db2828 dashed;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
<second-menu>
|
||||
<menu-item :href="'/ns/clusters/cluster?clusterId=' + currentCluster.id">{{currentCluster.name}}</menu-item>
|
||||
<span class="item disabled" style="padding-left: 0; padding-right: 0">»</span>
|
||||
<menu-item :href="'/ns/clusters/cluster?clusterId=' + clusterId">节点列表</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item :href="'/ns/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + nodeId" code="node">节点详情</menu-item>
|
||||
<menu-item :href="'/ns/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + nodeId" code="log">运行日志</menu-item>
|
||||
<menu-item :href="'/ns/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + nodeId" code="update">修改设置</menu-item>
|
||||
<menu-item :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + nodeId" code="install">安装节点</menu-item>
|
||||
</second-menu>
|
||||
@@ -0,0 +1,4 @@
|
||||
a.underline {
|
||||
border-bottom: 1px #db2828 dashed;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,CAAC;EACA,iCAAA","file":"index.css"}
|
||||
182
EdgeAdmin/web/views/@default/ns/clusters/cluster/node/index.html
Normal file
182
EdgeAdmin/web/views/@default/ns/clusters/cluster/node/index.html
Normal file
@@ -0,0 +1,182 @@
|
||||
{$layout}
|
||||
|
||||
{$template "node_menu"}
|
||||
|
||||
<h3>节点详情</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">节点名称</td>
|
||||
<td>{{node.name}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>状态</td>
|
||||
<td><label-on :v-is-on="node.isOn"></label-on></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP地址</td>
|
||||
<td>
|
||||
<div v-if="node.ipAddresses.length > 0">
|
||||
<div>
|
||||
<div v-for="(address, index) in node.ipAddresses" class="ui label tiny basic">
|
||||
{{address.ip}}
|
||||
<span class="small" v-if="address.name.length > 0">({{address.name}}<span v-if="!address.canAccess">,不公开访问</span>)</span>
|
||||
<span class="small red" v-if="!address.isOn">[off]</span>
|
||||
<span class="small red" v-if="!address.isUp">[down]</span>
|
||||
<span class="small" v-if="address.name.length == 0 && !address.canAccess">(不公开访问)</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="disabled">暂时还没有填写IP地址。</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>SSH主机地址</td>
|
||||
<td>
|
||||
<div v-if="node.login != null && node.login.params != null && node.login.params.host != null">
|
||||
<span v-if="node.login.params.host.length > 0">{{node.login.params.host}}</span>
|
||||
<span v-else class="disabled">尚未设置</span>
|
||||
</div>
|
||||
<div v-else class="disabled">
|
||||
尚未设置
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH主机端口</td>
|
||||
<td>
|
||||
<div v-if="node.login != null && node.login.params != null && node.login.params.host != null">
|
||||
<span v-if="node.login.params.port > 0">{{node.login.params.port}}</span>
|
||||
<span v-else class="disabled">尚未设置</span>
|
||||
</div>
|
||||
<span v-else class="disabled">
|
||||
尚未设置
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH登录认证</td>
|
||||
<td>
|
||||
<div v-if="node.login != null && node.login.grant != null && node.login.grant.id > 0">
|
||||
<a :href="'/clusters/grants/grant?grantId=' + node.login.grant.id">{{node.login.grant.name}}<span class="small grey">({{node.login.grant.methodName}})</span><span class="small grey" v-if="node.login.grant.username.length > 0">({{node.login.grant.username}})</span></a>
|
||||
</div>
|
||||
<span v-else class="disabled">
|
||||
尚未设置
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>API节点地址</td>
|
||||
<td>
|
||||
<div v-if="node.apiNodeAddrs != null && node.apiNodeAddrs.length > 0">
|
||||
<span v-for="addr in node.apiNodeAddrs" class="ui label basic small">{{addr}}</span>
|
||||
</div>
|
||||
<span v-else class="disabled">使用全局设置</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<div class="ui divider"></div>
|
||||
|
||||
<h3>运行状态</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">运行状态</td>
|
||||
<td>
|
||||
<div v-if="node.status.isActive">
|
||||
<span class="green">运行中</span>
|
||||
<a href="" @click.prevent="stopNode()" v-if="!isStopping"><span>[通过SSH停止]</span></a>
|
||||
<span v-if="isStopping">[停止中...]</span>
|
||||
</div>
|
||||
<div v-else>
|
||||
<span class="red">已断开</span>
|
||||
<a href="" @click.prevent="startNode()" v-if="node.isInstalled && !isStarting"><span>[通过SSH启动]</span></a>
|
||||
<span v-if="node.isInstalled && isStarting">[启动中...]</span>
|
||||
<a v-if="!node.isInstalled" :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" ><span>去安装></span></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody v-show="node.status.isActive">
|
||||
<tr>
|
||||
<td>CPU用量</td>
|
||||
<td>{{node.status.cpuUsageText}} <span v-if="node.status.cpuPhysicalCount > 0" class="small grey">({{node.status.cpuPhysicalCount}}核心/{{node.status.cpuLogicalCount}}线程)</span></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>内存用量</td>
|
||||
<td>{{node.status.memUsageText}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>负载</td>
|
||||
<td>{{node.status.load1m}} {{node.status.load5m}} {{node.status.load15m}} <tip-icon content="三个数字分别代表1分钟、5分钟、15分钟平均负载"></tip-icon></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
<tbody>
|
||||
<tr v-if="node.status.buildVersion != null && node.status.buildVersion.length > 0">
|
||||
<td>版本</td>
|
||||
<td>v{{node.status.buildVersion}}
|
||||
<a :href="'/ns/clusters/cluster/upgradeRemote?clusterId=' + clusterId" v-if="shouldUpgrade"><span class="red">发现新版本v{{newVersion}} »</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="node.status.exePath != null && node.status.exePath.length > 0">
|
||||
<td>主程序位置</td>
|
||||
<td>{{node.status.exePath}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>最近API连接状况</td>
|
||||
<td>
|
||||
<span v-if="node.status.apiSuccessPercent > 0 && node.status.apiAvgCostSeconds > 0">
|
||||
<span v-if="node.status.apiSuccessPercent <= 50" class="red">连接错误异常严重({{round(100 - node.status.apiSuccessPercent)}}%失败),请改善当前节点和API节点之间通讯</span>
|
||||
<span v-else-if="node.status.apiSuccessPercent <= 80" class="red">连接错误较多({{round(100 - node.status.apiSuccessPercent)}}%失败),请改善当前节点和API节点之间通讯</span>
|
||||
<span v-else-if="node.status.apiSuccessPercent < 100" class="orange">有连接错误发生({{round(100 - node.status.apiSuccessPercent)}}%失败),请改善当前节点和API节点之间通讯</span>
|
||||
<span v-else>
|
||||
<span v-if="node.status.apiAvgCostSeconds <= 1" class="green">连接良好</span>
|
||||
<span v-else-if="node.status.apiAvgCostSeconds <= 5" class="orange">连接基本稳定(平均{{round(node.status.apiAvgCostSeconds)}}秒)</span>
|
||||
<span v-else-if="node.status.apiAvgCostSeconds <= 10" class="orange">连接速度较慢(平均{{round(node.status.apiAvgCostSeconds)}}秒)</span>
|
||||
<span v-else class="red">连接非常慢(平均{{round(node.status.apiAvgCostSeconds)}}秒),请改善当前节点和API节点之间通讯</span>
|
||||
</span>
|
||||
</span>
|
||||
<span v-else class="disabled">尚未上报数据</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="nodeDatetime.length > 0">
|
||||
<td>上次更新时间</td>
|
||||
<td>
|
||||
{{nodeDatetime}}
|
||||
<p class="comment" v-if="nodeTimeDiff > 30"><span class="red">当前节点时间与API节点时间相差 {{nodeTimeDiff}} 秒,请同步节点时间。</span></p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p class="comment" v-if="node.status.isActive">每隔30秒钟更新一次运行状态。</p>
|
||||
|
||||
<div class="ui divider"></div>
|
||||
<h3>安装信息</h3>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td>节点ID<em>(id)</em></td>
|
||||
<td>{{node.uniqueId}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>密钥<em>(secret)</em></td>
|
||||
<td>{{node.secret}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">安装目录</td>
|
||||
<td>
|
||||
<div v-if="node.installDir.length == 0">使用集群设置<span v-if="node.cluster != null && node.cluster.installDir.length > 0">({{node.cluster.installDir}})</span></div>
|
||||
<span v-else>{{node.installDir}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>已安装</td>
|
||||
<td>
|
||||
<span v-if="node.isInstalled" class="green">已安装</span>
|
||||
<a v-else :href="'/ns/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + nodeId" class="underline" title="点击进入安装界面"><span class="red">未安装</span></a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
@@ -0,0 +1,39 @@
|
||||
Tea.context(function () {
|
||||
this.isStarting = false
|
||||
this.startNode = function () {
|
||||
this.isStarting = true
|
||||
this.$post("/ns/clusters/cluster/node/start")
|
||||
.params({
|
||||
nodeId: this.node.id
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("启动成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
.done(function () {
|
||||
this.isStarting = false
|
||||
})
|
||||
}
|
||||
|
||||
this.isStopping = false
|
||||
this.stopNode = function () {
|
||||
this.isStopping = true
|
||||
this.$post("/ns/clusters/cluster/node/stop")
|
||||
.params({
|
||||
nodeId: this.node.id
|
||||
})
|
||||
.success(function () {
|
||||
teaweb.success("执行成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
})
|
||||
.done(function () {
|
||||
this.isStopping = false
|
||||
})
|
||||
}
|
||||
|
||||
this.round = function (f) {
|
||||
return Math.round(f * 100) / 100
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
a.underline {
|
||||
border-bottom: 1px #db2828 dashed;
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
.installing-box {
|
||||
line-height: 1.8;
|
||||
}
|
||||
.installing-box .blue {
|
||||
color: #2185d0;
|
||||
}
|
||||
/*# sourceMappingURL=install.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["install.less"],"names":[],"mappings":"AAAA;EACC,gBAAA;;AADD,eAGC;EACC,cAAA","file":"install.css"}
|
||||
@@ -0,0 +1,98 @@
|
||||
{$layout}
|
||||
{$template "node_menu"}
|
||||
{$template "/code_editor"}
|
||||
|
||||
<!-- 已安装 -->
|
||||
<div v-if="node.isInstalled">
|
||||
<div class="ui message green">当前节点为已安装状态。</div>
|
||||
<a href="" @click.prevent="updateNodeIsInstalled(false)">[重新安装]</a>
|
||||
|
||||
<h4>配置文件</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">配置文件</td>
|
||||
<td>
|
||||
configs/api_dns.yaml
|
||||
<download-link :v-element="'rpc-code'" :v-file="'api_dns.yaml'">[下载]</download-link >
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>配置内容</td>
|
||||
<td>
|
||||
<source-code-box id="rpc-code" type="text/yaml">rpc.endpoints: [ {{apiEndpoints}} ]
|
||||
nodeId: "{{node.uniqueId}}"
|
||||
secret: "{{node.secret}}"</source-code-box>
|
||||
<p class="comment">每个节点的配置文件内容均不相同,不能混用。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">安装目录</td>
|
||||
<td>
|
||||
<div v-if="node.installDir.length == 0">使用集群设置<span
|
||||
v-if="node.cluster != null && node.cluster.installDir.length > 0">({{node.cluster.installDir}})</span>
|
||||
</div>
|
||||
<span v-else>{{node.installDir}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<!-- 未安装 -->
|
||||
<div v-if="!node.isInstalled">
|
||||
<h4>方法1:通过SSH自动安装</h4>
|
||||
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">SSH地址</td>
|
||||
<td>
|
||||
<span v-if="sshAddr.length > 0">{{sshAddr}} <a href="" @click.prevent="showSSHPopup(nodeId)">[修改]</a></span>
|
||||
<span v-else><span class="red">尚未设置</span> <a href="" @click.prevent="showSSHPopup(nodeId)">[设置]</a></span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-if="installStatus != null && (installStatus.isRunning || installStatus.isFinished)"
|
||||
class="ui segment installing-box">
|
||||
<div v-if="installStatus.isRunning" class="blue">安装中...</div>
|
||||
<div v-if="installStatus.isFinished">
|
||||
<span v-if="installStatus.isOk" class="green">已安装成功</span>
|
||||
<span v-if="!installStatus.isOk" class="red">安装过程中发生错误:{{installStatus.error}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="installStatus != null && installStatus.isFinished">
|
||||
<button class="ui button small" type="button" @click.prevent="install()">重新安装</button>
|
||||
</div>
|
||||
<div v-if="installStatus == null || (!installStatus.isFinished && !installStatus.isRunning)">
|
||||
<button class="ui button small primary" type="button" @click.prevent="install()">开始安装</button>
|
||||
</div>
|
||||
|
||||
<h4>方法2:手动安装</h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">配置文件</td>
|
||||
<td>
|
||||
configs/api_dns.yaml
|
||||
<download-link :v-element="'rpc-code'" :v-file="'api_dns.yaml'">[下载]</download-link >
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>配置内容</td>
|
||||
<td>
|
||||
<source-code-box id="rpc-code" type="text/yaml">rpc.endpoints: [ {{apiEndpoints}} ]
|
||||
nodeId: "{{node.uniqueId}}"
|
||||
secret: "{{node.secret}}"</source-code-box>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">安装目录</td>
|
||||
<td>
|
||||
<div v-if="node.installDir.length == 0">使用集群设置<span
|
||||
v-if="node.cluster != null && node.cluster.installDir.length > 0">({{node.cluster.installDir}})</span>
|
||||
</div>
|
||||
<span v-else>{{node.installDir}}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<a href="" @click.prevent="updateNodeIsInstalled(true)">[修改为已安装状态]</a>
|
||||
</div>
|
||||
117
EdgeAdmin/web/views/@default/ns/clusters/cluster/node/install.js
Normal file
117
EdgeAdmin/web/views/@default/ns/clusters/cluster/node/install.js
Normal file
@@ -0,0 +1,117 @@
|
||||
Tea.context(function () {
|
||||
let isInstalling = false
|
||||
|
||||
this.$delay(function () {
|
||||
this.reloadStatus(this.nodeId)
|
||||
})
|
||||
|
||||
// 开始安装
|
||||
this.install = function () {
|
||||
isInstalling = true
|
||||
|
||||
this.$post("$")
|
||||
.params({
|
||||
nodeId: this.nodeId
|
||||
})
|
||||
.success(function () {
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
// 设置节点安装状态
|
||||
this.updateNodeIsInstalled = function (isInstalled) {
|
||||
let msg = isInstalled ? "html:确定要将当前节点修改为<strong>已安装</strong>状态?" : "html:确定要将当前节点修改为<strong>未安装</strong>状态?"
|
||||
teaweb.confirm(msg, function () {
|
||||
this.$post("/ns/clusters/cluster/node/updateInstallStatus")
|
||||
.params({
|
||||
nodeId: this.nodeId,
|
||||
isInstalled: isInstalled ? 1 : 0
|
||||
})
|
||||
.refresh()
|
||||
})
|
||||
}
|
||||
|
||||
// 刷新状态
|
||||
this.reloadStatus = function (nodeId) {
|
||||
let that = this
|
||||
|
||||
this.$post("/ns/clusters/cluster/node/status")
|
||||
.params({
|
||||
nodeId: nodeId
|
||||
})
|
||||
.success(function (resp) {
|
||||
this.installStatus = resp.data.installStatus
|
||||
this.node.isInstalled = resp.data.isInstalled
|
||||
|
||||
if (!isInstalling) {
|
||||
return
|
||||
}
|
||||
|
||||
let nodeId = this.node.id
|
||||
let errMsg = this.installStatus.error
|
||||
|
||||
if (this.installStatus.errorCode.length > 0) {
|
||||
isInstalling = false
|
||||
}
|
||||
|
||||
switch (this.installStatus.errorCode) {
|
||||
case "EMPTY_LOGIN":
|
||||
case "EMPTY_SSH_HOST":
|
||||
case "EMPTY_SSH_PORT":
|
||||
case "EMPTY_GRANT":
|
||||
teaweb.warn("需要填写SSH登录信息", function () {
|
||||
teaweb.popup("/ns/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
that.install()
|
||||
}
|
||||
})
|
||||
})
|
||||
return
|
||||
case "SSH_LOGIN_FAILED":
|
||||
teaweb.warn("SSH登录失败,请检查设置", function () {
|
||||
teaweb.popup("/ns/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
that.install()
|
||||
}
|
||||
})
|
||||
})
|
||||
return
|
||||
case "CREATE_ROOT_DIRECTORY_FAILED":
|
||||
teaweb.warn("创建根目录失败,请检查目录权限或者手工创建:" + errMsg)
|
||||
return
|
||||
case "INSTALL_HELPER_FAILED":
|
||||
teaweb.warn("安装助手失败:" + errMsg)
|
||||
return
|
||||
case "TEST_FAILED":
|
||||
teaweb.warn("环境测试失败:" + errMsg)
|
||||
return
|
||||
case "RPC_TEST_FAILED":
|
||||
teaweb.confirm("html:要安装的节点到API服务之间的RPC通讯测试失败,具体错误:" + errMsg + ",<br/>现在修改API信息?", function () {
|
||||
window.location = "/settings/api"
|
||||
})
|
||||
return
|
||||
default:
|
||||
shouldReload = true
|
||||
//teaweb.warn("安装失败:" + errMsg)
|
||||
}
|
||||
})
|
||||
.done(function () {
|
||||
this.$delay(function () {
|
||||
this.reloadStatus(nodeId)
|
||||
}, 1000)
|
||||
});
|
||||
}
|
||||
|
||||
this.showSSHPopup = function (nodeId) {
|
||||
teaweb.popup("/ns/clusters/cluster/updateNodeSSH?nodeId=" + nodeId, {
|
||||
height: "30em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
teaweb.reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
.installing-box {
|
||||
line-height: 1.8;
|
||||
|
||||
.blue {
|
||||
color: #2185d0;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
pre.log-box {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
/*# sourceMappingURL=logs.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["logs.less"],"names":[],"mappings":"AAAA,GAAG;EACF,SAAA;EACA,UAAA","file":"logs.css"}
|
||||
@@ -0,0 +1,51 @@
|
||||
{$layout}
|
||||
{$template "node_menu"}
|
||||
{$template "/datepicker"}
|
||||
|
||||
<form method="get" action="/ns/clusters/cluster/node/logs" class="ui form" autocomplete="off">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<input type="hidden" name="nodeId" :value="nodeId"/>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="dayFrom" placeholder="开始日期" v-model="dayFrom" value="" style="width:8em" id="day-from-picker"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="dayTo" placeholder="结束日期" v-model="dayTo" value="" style="width:8em" id="day-to-picker"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="level" v-model="level">
|
||||
<option value="">[级别]</option>
|
||||
<option value="error">错误</option>
|
||||
<option value="warning">警告</option>
|
||||
<option value="info">信息</option>
|
||||
<option value="success">成功</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" style="width:10em" v-model="keyword" placeholder="关键词"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">查询</button>
|
||||
</div>
|
||||
<div class="ui field" v-if="dayFrom.length > 0 || dayTo.length > 0 || keyword.length > 0 || level.length > 0">
|
||||
<a :href="'/ns/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + nodeId">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||
|
||||
<table class="ui table selectable" v-if="logs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="log in logs">
|
||||
<td>
|
||||
<node-log-row :v-log="log" :v-keyword="keyword"></node-log-row>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
@@ -0,0 +1,6 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
teaweb.datepicker("day-from-picker")
|
||||
teaweb.datepicker("day-to-picker")
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,4 @@
|
||||
pre.log-box {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
{$layout}
|
||||
|
||||
{$template "node_menu"}
|
||||
|
||||
<h3>修改节点</h3>
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="nodeId" :value="node.id"/>
|
||||
<input type="hidden" name="loginId" :value="loginId"/>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">节点名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="node.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP地址 *</td>
|
||||
<td>
|
||||
<node-ip-addresses-box role="ns" :v-ip-addresses="node.ipAddresses"></node-ip-addresses-box>
|
||||
<p class="comment">用于访问节点和域名解析等。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属集群</td>
|
||||
<td>
|
||||
<select class="ui dropdown" name="clusterId" style="width:10em" v-model="clusterId">
|
||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>SSH主机地址</td>
|
||||
<td>
|
||||
<input type="text" name="sshHost" maxlength="64" v-model="sshHost"/>
|
||||
<p class="comment">比如192.168.1.100</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH主机端口</td>
|
||||
<td>
|
||||
<input type="text" name="sshPort" maxlength="5" v-model="sshPort"/>
|
||||
<p class="comment">比如22。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH登录认证</td>
|
||||
<td>
|
||||
<grant-selector :v-grant="grant" :v-ns-cluster-id="clusterId"></grant-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">API节点地址</td>
|
||||
<td>
|
||||
<div style="margin-bottom: 0.5em">
|
||||
<api-node-addresses-box :v-name="'apiNodeAddrsJSON'" :v-addrs="apiNodeAddrs"></api-node-addresses-box>
|
||||
</div>
|
||||
<p class="comment">当前节点单独使用的API节点设置。<pro-warning-label></pro-warning-label></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前节点</td>
|
||||
<td>
|
||||
<div class="ui checkbox">
|
||||
<input type="checkbox" name="isOn" value="1" v-model="node.isOn"/>
|
||||
<label></label>
|
||||
</div>
|
||||
<p class="comment">如果不启用此节点,此节点上的所有网站将不能访问。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,35 @@
|
||||
Tea.context(function () {
|
||||
this.clusterId = 0;
|
||||
if (this.node.cluster != null && this.node.cluster.id > 0) {
|
||||
this.clusterId = this.node.cluster.id;
|
||||
}
|
||||
|
||||
this.success = NotifySuccess("保存成功", "/ns/clusters/cluster/node?clusterId=" + this.clusterId + "&nodeId=" + this.node.id);
|
||||
|
||||
// 认证相关
|
||||
this.grant = null
|
||||
|
||||
this.sshHost = ""
|
||||
this.sshPort = ""
|
||||
this.loginId = 0
|
||||
if (this.node.login != null) {
|
||||
this.loginId = this.node.login.id
|
||||
|
||||
if (this.node.login.params != null) {
|
||||
this.sshHost = this.node.login.params.host
|
||||
if (this.node.login.params.port > 0) {
|
||||
this.sshPort = this.node.login.params.port
|
||||
}
|
||||
}
|
||||
|
||||
if (this.node.login.grant != null && typeof this.node.login.grant.id != "undefined") {
|
||||
this.grant = {
|
||||
id: this.node.login.grant.id,
|
||||
name: this.node.login.grant.name,
|
||||
method: this.node.login.grant.method,
|
||||
methodName: this.node.login.grant.methodName,
|
||||
username: this.node.login.grant.username
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,7 @@
|
||||
<second-menu>
|
||||
<menu-item :href="'/ns/clusters/cluster?clusterId=' + currentCluster.id">{{currentCluster.name}}</menu-item>
|
||||
<raquo-item></raquo-item>
|
||||
<menu-item :href="'/ns/clusters/cluster/settings?clusterId=' + currentCluster">集群设置</menu-item>
|
||||
<raquo-item></raquo-item>
|
||||
<a class="item active" v-if="leftMenuActiveItem != null" :href="leftMenuActiveItem.url">"{{leftMenuActiveItem.name}}"设置</a>
|
||||
</second-menu>
|
||||
@@ -0,0 +1,12 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<ns-access-log-ref-box :v-access-log-ref="accessLogRef" :v-is-parent="false"></ns-access-log-ref-box>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,27 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">应答模式 *</td>
|
||||
<td>
|
||||
<select name="mode" class="ui dropdown auto-width" v-model="config.mode">
|
||||
<option v-for="mode in modes" :value="mode.code">{{mode.name}}</option>
|
||||
</select>
|
||||
<p class="comment" v-for="mode in modes" v-if="mode.code == config.mode">{{mode.description}}</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="config.mode == 'random'">
|
||||
<td>最多结果数量</td>
|
||||
<td>
|
||||
<input type="text" name="maxSize" v-model="config.maxSize"/>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,19 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<first-menu>
|
||||
<menu-item :href="'.?clusterId=' + clusterId" class="active">设置</menu-item>
|
||||
<menu-item :href="'.status?clusterId=' + clusterId" >状态</menu-item>
|
||||
</first-menu>
|
||||
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
|
||||
<ns-node-ddos-protection-config-box :v-ddos-protection-config="config" :v-default-configs="defaultConfigs"></ns-node-ddos-protection-config-box>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,44 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<first-menu>
|
||||
<menu-item :href="'.?clusterId=' + clusterId">设置</menu-item>
|
||||
<menu-item :href="'.status?clusterId=' + clusterId" class="active">状态</menu-item>
|
||||
</first-menu>
|
||||
|
||||
<loading-message v-if="isLoading">检查中,请耐心等待完成...</loading-message>
|
||||
|
||||
<p class="comment" v-if="!isLoading && results.length == 0">当前集群下暂时还没有节点。</p>
|
||||
|
||||
<table class="ui table selectable" v-if="results.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="three wide">节点名称</th>
|
||||
<th>检查结果</th>
|
||||
<!--<th class="two op">独立设置</th>-->
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="result in results">
|
||||
<tr>
|
||||
<td>
|
||||
<a :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + result.nodeId">{{result.nodeName}}</a>
|
||||
<div v-if="result.isPrior">
|
||||
<a :href="'/clusters/cluster/node/settings/ddos-protection?clusterId=' + clusterId + '&nodeId=' + result.nodeId"><grey-label>定制</grey-label></a>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<span class="green" v-if="result.isOk">{{result.message}}</span>
|
||||
<span class="red" v-if="!result.isOk">{{result.message}}</span>
|
||||
</td>
|
||||
<!--<td>
|
||||
<a :href="'/clusters/cluster/node/settings/ddos-protection?clusterId=' + clusterId + '&nodeId=' + result.nodeId">设置</a>
|
||||
</td>-->
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div class="margin"></div>
|
||||
<a href="" @click.prevent="reload">[刷新]</a>
|
||||
</div>
|
||||
@@ -0,0 +1,20 @@
|
||||
Tea.context(function () {
|
||||
this.isLoading = true
|
||||
this.results = []
|
||||
|
||||
this.$delay(function () {
|
||||
this.reload()
|
||||
})
|
||||
|
||||
this.reload = function () {
|
||||
this.isLoading = true
|
||||
this.$post("$")
|
||||
.params({ clusterId: this.clusterId })
|
||||
.success(function (resp) {
|
||||
this.results = resp.data.results
|
||||
})
|
||||
.done(function () {
|
||||
this.isLoading = false
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,34 @@
|
||||
{$layout}
|
||||
|
||||
{$var "header"}
|
||||
<script src="/servers/certs/datajs" type="text/javascript"></script>
|
||||
<script src="/js/sortable.min.js" type="text/javascript"></script>
|
||||
{$end}
|
||||
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">启用DoH</td>
|
||||
<td>
|
||||
<checkbox name="isOn" v-model="dohConfig.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-show="dohConfig.isOn">
|
||||
<td class="title">绑定端口 *</td>
|
||||
<td>
|
||||
<network-addresses-box :v-url="'/ns/addPortPopup'" :v-addresses="dohConfig.listen" :v-protocol="'tls'" :v-support-range="false"></network-addresses-box>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- SSL配置 -->
|
||||
<ssl-config-box :v-ssl-policy="dohConfig.sslPolicy" :v-protocol="'tls'" v-show="dohConfig.isOn"></ssl-config-box>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,80 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="clusterId" :value="cluster.id"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">集群名称 *</td>
|
||||
<td><input type="text" name="name" maxlength="50" ref="focus" v-model="cluster.name"/></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>管理员电子邮箱 *</td>
|
||||
<td><input type="text" name="email" placeholder="比如 joe@example.org" v-model="cluster.email"/>
|
||||
<p class="comment">域名管理员电子邮箱地址,用于生成SOA记录等处。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">DNS主机域名</td>
|
||||
<td>
|
||||
<values-box name="hosts" placeholder="比如 ns1.example.com" :v-values="cluster.hosts"></values-box>
|
||||
<p class="comment">类似于<code-label>ns1.example.com</code-label>;需要确保这些域名已经解析到集群节点;同时用户需要将DNS主机地址修改为这些域名,然后才可以在我们系统中修改域名解析。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"><more-options-indicator></more-options-indicator></td>
|
||||
</tr>
|
||||
<tbody v-show="moreOptionsVisible">
|
||||
<tr>
|
||||
<td>时区</td>
|
||||
<td>
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" v-model="timeZoneGroupCode">
|
||||
<option v-for="timeZoneGroup in timeZoneGroups" :value="timeZoneGroup.code">{{timeZoneGroup.name}}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="timeZone" v-model="cluster.timeZone">
|
||||
<option v-for="timeZoneLocation in timeZoneLocations" :value="timeZoneLocation.name" v-if="timeZoneLocation.group == timeZoneGroupCode">{{timeZoneLocation.name}} ({{timeZoneLocation.offset}})</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<p class="comment">节点记录日志使用的时区。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>自动远程启动</td>
|
||||
<td>
|
||||
<checkbox name="autoRemoteStart" v-model="cluster.autoRemoteStart"></checkbox>
|
||||
<p class="comment">当检测到节点离线时,自动尝试远程启动(前提是节点已经设置了SSH登录认证)。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>监测搜索引擎</td>
|
||||
<td>
|
||||
<checkbox name="detectAgents" v-model="cluster.detectAgents"></checkbox>
|
||||
<p class="comment">实时检测访问DNS的IP是否为常见搜索引擎,发现相关数据后会自动加入到IP数据库中,以实现搜索引擎线路相关功能;此功能需要消耗一定的网络流量用来查询IP相关记录。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>自动检测端口</td>
|
||||
<td>
|
||||
<checkbox name="checkingPorts" v-model="cluster.checkingPorts"></checkbox>
|
||||
<p class="comment">选中后,表示自动检测节点端口连通性,并在节点列表页提示异常;目前仅支持检测UDP端口;如果当前系统所在服务器UDP无法正常通讯,请关闭此选项。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>启用当前集群</td>
|
||||
<td>
|
||||
<checkbox name="isOn" value="1" v-model="cluster.isOn"></checkbox>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,35 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
|
||||
this.timeZoneGroupCode = "asia"
|
||||
if (this.timeZoneLocation != null) {
|
||||
this.timeZoneGroupCode = this.timeZoneLocation.group
|
||||
}
|
||||
|
||||
let oldTimeZoneGroupCode = this.timeZoneGroupCode
|
||||
let oldTimeZoneName = ""
|
||||
if (this.timeZoneLocation != null) {
|
||||
oldTimeZoneName = this.timeZoneLocation.name
|
||||
}
|
||||
|
||||
this.$delay(function () {
|
||||
this.$watch("timeZoneGroupCode", function (groupCode) {
|
||||
if (groupCode == oldTimeZoneGroupCode && oldTimeZoneName.length > 0) {
|
||||
this.cluster.timeZone = oldTimeZoneName
|
||||
return
|
||||
}
|
||||
let firstLocation = null
|
||||
this.timeZoneLocations.forEach(function (v) {
|
||||
if (firstLocation != null) {
|
||||
return
|
||||
}
|
||||
if (v.group == groupCode) {
|
||||
firstLocation = v
|
||||
}
|
||||
})
|
||||
if (firstLocation != null) {
|
||||
this.cluster.timeZone = firstLocation.name
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
@@ -0,0 +1,13 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
|
||||
<ns-recursion-config-box :v-recursion-config="config"></ns-recursion-config-box>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,62 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">主要服务器名称</td>
|
||||
<td>
|
||||
<input type="text" name="mName" value="" v-model="config.mName" maxlength="128" ref="focus"/>
|
||||
<p class="comment">不填表示默认为从<a :href="'/ns/clusters/cluster/settings?clusterId=' + clusterId">DNS主机域名</a>中随机选取一个。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>管理员电子邮箱</td>
|
||||
<td>
|
||||
<input type="text" name="rName" value="" v-model="config.rName" maxlength="128"/>
|
||||
<p class="comment">不填表示使用集群设置的<a :href="'/ns/clusters/cluster/settings?clusterId=' + clusterId">管理员电子邮箱</a>。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>刷新时间间隔</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="refreshSeconds" v-model="config.refreshSeconds" style="width: 7em" maxlength="10"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>重试时间间隔</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="retrySeconds" v-model="config.retrySeconds" style="width: 7em" maxlength="10"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>过期时间间隔</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="expireSeconds" v-model="config.expireSeconds" style="width: 7em" maxlength="10"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>TTL</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="minimumTTL" v-model="config.minimumTTL" style="width: 7em" maxlength="10"/>
|
||||
<span class="ui label">秒</span>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">绑定端口 *</td>
|
||||
<td>
|
||||
<network-addresses-box :v-url="'/ns/addPortPopup'" :v-addresses="tcpConfig.listen" :v-protocol="'tcp'" :v-support-range="true"></network-addresses-box>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,28 @@
|
||||
{$layout}
|
||||
|
||||
{$var "header"}
|
||||
<script src="/servers/certs/datajs" type="text/javascript"></script>
|
||||
<script src="/js/sortable.min.js" type="text/javascript"></script>
|
||||
{$end}
|
||||
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">绑定端口 *</td>
|
||||
<td>
|
||||
<network-addresses-box :v-url="'/ns/addPortPopup'" :v-addresses="tlsConfig.listen" :v-protocol="'tls'" :v-support-range="true"></network-addresses-box>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<!-- SSL配置 -->
|
||||
<ssl-config-box :v-ssl-policy="tlsConfig.sslPolicy" :v-protocol="'tls'" v-show="tlsConfig.isOn"></ssl-config-box>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,18 @@
|
||||
{$layout}
|
||||
{$template "../menu"}
|
||||
{$template "/left_menu_with_menu"}
|
||||
|
||||
<div class="right-box with-menu">
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="clusterId" :value="clusterId"/>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">绑定端口 *</td>
|
||||
<td>
|
||||
<network-addresses-box :v-url="'/ns/addPortPopup'" :v-addresses="udpConfig.listen" :v-protocol="'udp'" :v-support-range="true"></network-addresses-box>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
</div>
|
||||
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifyReloadSuccess("保存成功")
|
||||
})
|
||||
@@ -0,0 +1,31 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>修改节点"{{node.name}}"的SSH登录信息</h3>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<input type="hidden" name="nodeId" :value="node.id"/>
|
||||
<input type="hidden" name="loginId" :value="loginId"/>
|
||||
<table class="ui table definition">
|
||||
<tr>
|
||||
<td class="title">SSH主机地址 *</td>
|
||||
<td>
|
||||
<input type="text" name="sshHost" maxlength="64" v-model="params.host" ref="focus"/>
|
||||
<p class="comment">比如192.168.1.100</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH主机端口 *</td>
|
||||
<td>
|
||||
<input type="text" name="sshPort" maxlength="5" v-model="params.port" style="width:6em"/>
|
||||
<p class="comment">比如22。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SSH登录认证 *</td>
|
||||
<td>
|
||||
<grant-selector :v-grant="grant" :v-ns-cluster-id="clusterId"></grant-selector>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
@@ -0,0 +1,5 @@
|
||||
Tea.context(function () {
|
||||
if (this.params.port <= 0) {
|
||||
this.params.port = 22
|
||||
}
|
||||
})
|
||||
@@ -0,0 +1,3 @@
|
||||
{$layout}
|
||||
|
||||
<p class="ui message error">此功能暂未开放。</p>
|
||||
37
EdgeAdmin/web/views/@default/ns/clusters/create.html
Normal file
37
EdgeAdmin/web/views/@default/ns/clusters/create.html
Normal file
@@ -0,0 +1,37 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<div class="ui margin"></div>
|
||||
<form class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
<csrf-token></csrf-token>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">集群名称 *</td>
|
||||
<td>
|
||||
<input type="text" name="name" maxlength="50" ref="focus" placeholder=""/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>管理员电子邮箱 *</td>
|
||||
<td><input type="text" name="email" placeholder="比如 joe@example.org"/>
|
||||
<p class="comment">域名管理员电子邮箱地址,用于生成SOA记录等处。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>DNS主机域名<span style="font-size: 0.7em; color: grey">(DNS Hosts)</span></h4>
|
||||
<table class="ui table definition selectable">
|
||||
<tr>
|
||||
<td class="title">DNS主机域名</td>
|
||||
<td>
|
||||
<values-box name="hosts" placeholder="比如 ns1.example.com"></values-box>
|
||||
<p class="comment">类似于<code-label>ns1.example.com</code-label>;需要确保这些域名已经解析到集群节点。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>访问日志设置</h4>
|
||||
<ns-access-log-ref-box :v-access-log-ref="accessLogRef"></ns-access-log-ref-box>
|
||||
|
||||
<submit-btn></submit-btn>
|
||||
</form>
|
||||
3
EdgeAdmin/web/views/@default/ns/clusters/create.js
Normal file
3
EdgeAdmin/web/views/@default/ns/clusters/create.js
Normal file
@@ -0,0 +1,3 @@
|
||||
Tea.context(function () {
|
||||
this.success = NotifySuccess("保存成功", "/ns/clusters")
|
||||
})
|
||||
31
EdgeAdmin/web/views/@default/ns/clusters/index.css
Normal file
31
EdgeAdmin/web/views/@default/ns/clusters/index.css
Normal file
@@ -0,0 +1,31 @@
|
||||
.cluster-name-td {
|
||||
position: relative;
|
||||
}
|
||||
.cluster-name-td .icon.pin {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 50%;
|
||||
margin-top: -0.7em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
.cluster-name-td .icon.visible {
|
||||
display: inline;
|
||||
}
|
||||
.cluster-name-td .icon.opacity {
|
||||
opacity: 0.3;
|
||||
}
|
||||
.cluster-name-td .icon.setting {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 3em;
|
||||
top: 50%;
|
||||
margin-top: -0.7em;
|
||||
}
|
||||
.cluster-name-td:hover .icon.pin {
|
||||
display: inline;
|
||||
}
|
||||
.cluster-name-td:hover .icon.setting {
|
||||
display: inline;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
1
EdgeAdmin/web/views/@default/ns/clusters/index.css.map
Normal file
1
EdgeAdmin/web/views/@default/ns/clusters/index.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA;EACC,kBAAA;;AADD,gBAGC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,kBAAA;EACA,YAAA;;AATF,gBAYC,MAAK;EACJ,eAAA;;AAbF,gBAgBC,MAAK;EACJ,YAAA;;AAjBF,gBAoBC,MAAK;EACJ,aAAA;EACA,kBAAA;EACA,UAAA;EACA,QAAA;EACA,kBAAA;;AAIF,gBAAgB,MACf,MAAK;EACJ,eAAA;;AAFF,gBAAgB,MAIf,MAAK;EACJ,eAAA","file":"index.css"}
|
||||
47
EdgeAdmin/web/views/@default/ns/clusters/index.html
Normal file
47
EdgeAdmin/web/views/@default/ns/clusters/index.html
Normal file
@@ -0,0 +1,47 @@
|
||||
{$layout}
|
||||
{$template "menu"}
|
||||
|
||||
<p class="comment" v-if="clusters.length == 0">暂时还没有集群。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="clusters.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>集群名称</th>
|
||||
<th class="center width10">节点数</th>
|
||||
<th class="center width10">在线节点数</th>
|
||||
<th class="center width10">域名数</th>
|
||||
<th class="width5">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="cluster in clusters">
|
||||
<td class="cluster-name-td"><a :href="'/ns/clusters/cluster?clusterId=' + cluster.id">{{cluster.name}}</a>
|
||||
|
||||
<a :href="'/ns/clusters/cluster/settings?clusterId=' + cluster.id" title="设置"><i class="icon setting grey"></i></a>
|
||||
</td>
|
||||
<td class="center">
|
||||
<a :href="'/ns/clusters/cluster?clusterId=' + cluster.id" v-if="cluster.countAllNodes > 0"><span :class="{red:cluster.countAllNodes > cluster.countActiveNodes}">{{cluster.countAllNodes}}</span></a>
|
||||
<span class="disabled" v-else="">-</span>
|
||||
|
||||
<div v-if="cluster.countUpgradeNodes > 0" style="margin-top:0.5em">
|
||||
<a :href="'/ns/clusters/cluster?clusterId=' + cluster.id" title="点击进入远程升级页面"><span class="red">有节点需要升级</span></a>
|
||||
</div>
|
||||
</td>
|
||||
<td class="center">
|
||||
<a :href="'/ns/clusters/cluster?clusterId=' + cluster.id + '&activeState=1'" v-if="cluster.countActiveNodes > 0"><span class="green">{{cluster.countActiveNodes}}</span></a>
|
||||
<span class="disabled" v-else>-</span>
|
||||
</td>
|
||||
<td class="center">
|
||||
<span v-if="cluster.countDomains > 0">{{cluster.countDomains}}</span>
|
||||
<span v-else class="disabled">-</span>
|
||||
</td>
|
||||
<td>
|
||||
<label-on :v-is-on="cluster.isOn"></label-on>
|
||||
</td>
|
||||
<td>
|
||||
<a :href="'/ns/clusters/cluster?clusterId=' + cluster.id">详情</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
37
EdgeAdmin/web/views/@default/ns/clusters/index.less
Normal file
37
EdgeAdmin/web/views/@default/ns/clusters/index.less
Normal file
@@ -0,0 +1,37 @@
|
||||
.cluster-name-td {
|
||||
position: relative;
|
||||
|
||||
.icon.pin {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 1em;
|
||||
top: 50%;
|
||||
margin-top: -0.7em;
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.icon.visible {
|
||||
display: inline;
|
||||
}
|
||||
|
||||
.icon.opacity {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.icon.setting {
|
||||
display: none;
|
||||
position: absolute;
|
||||
right: 3em;
|
||||
top: 50%;
|
||||
margin-top: -0.7em;
|
||||
}
|
||||
}
|
||||
|
||||
.cluster-name-td:hover {
|
||||
.icon.pin {
|
||||
display: inline;
|
||||
}
|
||||
.icon.setting {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
5
EdgeAdmin/web/views/@default/ns/clusters/logs/index.css
Normal file
5
EdgeAdmin/web/views/@default/ns/clusters/logs/index.css
Normal file
@@ -0,0 +1,5 @@
|
||||
pre.log-box {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
/*# sourceMappingURL=index.css.map */
|
||||
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["index.less"],"names":[],"mappings":"AAAA,GAAG;EACF,SAAA;EACA,UAAA","file":"index.css"}
|
||||
55
EdgeAdmin/web/views/@default/ns/clusters/logs/index.html
Normal file
55
EdgeAdmin/web/views/@default/ns/clusters/logs/index.html
Normal file
@@ -0,0 +1,55 @@
|
||||
{$layout}
|
||||
{$template "/datepicker"}
|
||||
|
||||
|
||||
<div class="margin"></div>
|
||||
|
||||
<form method="get" action="/ns/clusters/logs" class="ui form" autocomplete="off">
|
||||
<div class="ui fields inline">
|
||||
<div class="ui field">
|
||||
<input type="text" name="dayFrom" placeholder="开始日期" v-model="dayFrom" value="" style="width:8em" id="day-from-picker"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="dayTo" placeholder="结束日期" v-model="dayTo" value="" style="width:8em" id="day-to-picker"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown" name="level" v-model="level">
|
||||
<option value="">[级别]</option>
|
||||
<option value="error">错误</option>
|
||||
<option value="warning">警告</option>
|
||||
<option value="info">信息</option>
|
||||
<option value="success">成功</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<input type="text" name="keyword" style="width:10em" v-model="keyword" placeholder="关键词"/>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
<button type="submit" class="ui button">查询</button>
|
||||
</div>
|
||||
<div class="ui field" v-if="dayFrom.length > 0 || dayTo.length > 0 || keyword.length > 0 || level.length > 0">
|
||||
<a href="/ns/clusters/logs">[清除条件]</a>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<p class="comment" v-if="logs.length == 0">暂时还没有日志。</p>
|
||||
|
||||
<table class="ui table selectable celled" v-if="logs.length > 0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>集群</th>
|
||||
<th>节点</th>
|
||||
<th>信息</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="log in logs">
|
||||
<td nowrap=""><link-icon :href="'/ns/clusters/cluster?clusterId=' + log.node.cluster.id">{{log.node.cluster.name}}</link-icon></td>
|
||||
<td nowrap=""><link-icon :href="'/ns/clusters/cluster/node?clusterId=' + log.node.cluster.id + '&nodeId=' + log.node.id">{{log.node.name}}</link-icon></td>
|
||||
<td>
|
||||
<node-log-row :v-log="log" :v-keyword="keyword"></node-log-row>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div class="page" v-html="page"></div>
|
||||
6
EdgeAdmin/web/views/@default/ns/clusters/logs/index.js
Normal file
6
EdgeAdmin/web/views/@default/ns/clusters/logs/index.js
Normal file
@@ -0,0 +1,6 @@
|
||||
Tea.context(function () {
|
||||
this.$delay(function () {
|
||||
teaweb.datepicker("day-from-picker")
|
||||
teaweb.datepicker("day-to-picker")
|
||||
})
|
||||
})
|
||||
4
EdgeAdmin/web/views/@default/ns/clusters/logs/index.less
Normal file
4
EdgeAdmin/web/views/@default/ns/clusters/logs/index.less
Normal file
@@ -0,0 +1,4 @@
|
||||
pre.log-box {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
Reference in New Issue
Block a user