- Add cluster server list and assign page and client list page (for a specific app) Signed-off-by: Eric Zhao <sczyh16@gmail.com>master
@@ -67,15 +67,15 @@ angular | |||||
}) | }) | ||||
.state('dashboard.flowV1', { | .state('dashboard.flowV1', { | ||||
templateUrl: 'app/views/flow_old.html', | |||||
url: '/v1/flow/:app', | |||||
templateUrl: 'app/views/flow_v1.html', | |||||
url: '/flow/:app', | |||||
controller: 'FlowControllerV1', | controller: 'FlowControllerV1', | ||||
resolve: { | resolve: { | ||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | ||||
return $ocLazyLoad.load({ | return $ocLazyLoad.load({ | ||||
name: 'sentinelDashboardApp', | name: 'sentinelDashboardApp', | ||||
files: [ | files: [ | ||||
'app/scripts/controllers/flow_old.js', | |||||
'app/scripts/controllers/flow_v1.js', | |||||
] | ] | ||||
}); | }); | ||||
}] | }] | ||||
@@ -83,15 +83,15 @@ angular | |||||
}) | }) | ||||
.state('dashboard.flow', { | .state('dashboard.flow', { | ||||
templateUrl: 'app/views/flow.html', | |||||
url: '/flow/:app', | |||||
controller: 'FlowController', | |||||
templateUrl: 'app/views/flow_v2.html', | |||||
url: '/v2/flow/:app', | |||||
controller: 'FlowControllerV2', | |||||
resolve: { | resolve: { | ||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | ||||
return $ocLazyLoad.load({ | return $ocLazyLoad.load({ | ||||
name: 'sentinelDashboardApp', | name: 'sentinelDashboardApp', | ||||
files: [ | files: [ | ||||
'app/scripts/controllers/flow.js', | |||||
'app/scripts/controllers/flow_v2.js', | |||||
] | ] | ||||
}); | }); | ||||
}] | }] | ||||
@@ -114,16 +114,64 @@ angular | |||||
} | } | ||||
}) | }) | ||||
.state('dashboard.clusterAll', { | |||||
templateUrl: 'app/views/cluster.html', | |||||
url: '/cluster/:app', | |||||
controller: 'SentinelClusterController', | |||||
.state('dashboard.clusterAppAssignManage', { | |||||
templateUrl: 'app/views/cluster_app_assign_manage.html', | |||||
url: '/cluster/assign_manage/:app', | |||||
controller: 'SentinelClusterAppAssignManageController', | |||||
resolve: { | resolve: { | ||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | ||||
return $ocLazyLoad.load({ | return $ocLazyLoad.load({ | ||||
name: 'sentinelDashboardApp', | name: 'sentinelDashboardApp', | ||||
files: [ | files: [ | ||||
'app/scripts/controllers/cluster.js', | |||||
'app/scripts/controllers/cluster_app_assign_manage.js', | |||||
] | |||||
}); | |||||
}] | |||||
} | |||||
}) | |||||
.state('dashboard.clusterAppServerList', { | |||||
templateUrl: 'app/views/cluster_app_server_list.html', | |||||
url: '/cluster/server/:app', | |||||
controller: 'SentinelClusterAppServerListController', | |||||
resolve: { | |||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | |||||
return $ocLazyLoad.load({ | |||||
name: 'sentinelDashboardApp', | |||||
files: [ | |||||
'app/scripts/controllers/cluster_app_server_list.js', | |||||
] | |||||
}); | |||||
}] | |||||
} | |||||
}) | |||||
.state('dashboard.clusterAppClientList', { | |||||
templateUrl: 'app/views/cluster_app_client_list.html', | |||||
url: '/cluster/client/:app', | |||||
controller: 'SentinelClusterAppTokenClientListController', | |||||
resolve: { | |||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | |||||
return $ocLazyLoad.load({ | |||||
name: 'sentinelDashboardApp', | |||||
files: [ | |||||
'app/scripts/controllers/cluster_app_token_client_list.js', | |||||
] | |||||
}); | |||||
}] | |||||
} | |||||
}) | |||||
.state('dashboard.clusterSingle', { | |||||
templateUrl: 'app/views/cluster_single_config.html', | |||||
url: '/cluster/single/:app', | |||||
controller: 'SentinelClusterSingleController', | |||||
resolve: { | |||||
loadMyFiles: ['$ocLazyLoad', function ($ocLazyLoad) { | |||||
return $ocLazyLoad.load({ | |||||
name: 'sentinelDashboardApp', | |||||
files: [ | |||||
'app/scripts/controllers/cluster_single.js', | |||||
] | ] | ||||
}); | }); | ||||
}] | }] | ||||
@@ -224,4 +272,4 @@ angular | |||||
}] | }] | ||||
} | } | ||||
}); | }); | ||||
}]); | |||||
}]); |
@@ -0,0 +1,283 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('SentinelClusterAppAssignManageController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | |||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | |||||
$scope.app = $stateParams.app; | |||||
const UNSUPPORTED_CODE = 4041; | |||||
const CLUSTER_MODE_CLIENT = 0; | |||||
const CLUSTER_MODE_SERVER = 1; | |||||
const DEFAULT_CLUSTER_SERVER_PORT = 18730; | |||||
$scope.tmp = { | |||||
curClientChosen: [], | |||||
curRemainingClientChosen: [], | |||||
curChosenServer: {}, | |||||
}; | |||||
function convertSetToString(set) { | |||||
if (set === undefined) { | |||||
return ''; | |||||
} | |||||
let s = ''; | |||||
for (let i = 0; i < set.length; i++) { | |||||
s = s + set[i]; | |||||
if (i < set.length - 1) { | |||||
s = s + ','; | |||||
} | |||||
} | |||||
return s; | |||||
} | |||||
function convertStrToNamespaceSet(str) { | |||||
if (str === undefined || str === '') { | |||||
return []; | |||||
} | |||||
let arr = []; | |||||
let spliced = str.split(','); | |||||
spliced.forEach((v) => { | |||||
arr.push(v.trim()); | |||||
}); | |||||
return arr; | |||||
} | |||||
function processAppSingleData(data) { | |||||
if (data.state.server && data.state.server.namespaceSet) { | |||||
data.state.server.namespaceSetStr = convertSetToString(data.state.server.namespaceSet); | |||||
data.mode = data.state.stateInfo.mode; | |||||
} | |||||
} | |||||
function removeFromArr(arr, v) { | |||||
for (let i = 0; i < arr.length; i++) { | |||||
if (arr[i] === v) { | |||||
arr.splice(i, 1); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
function resetChosen() { | |||||
$scope.tmp.curClientChosen = []; | |||||
$scope.tmp.curRemainingClientChosen = []; | |||||
} | |||||
function generateMachineId(e) { | |||||
return e.ip + '@' + e.commandPort; | |||||
} | |||||
function applyClusterMap(appClusterMachineList) { | |||||
if (!appClusterMachineList) { | |||||
return; | |||||
} | |||||
let tmpMap = new Map(); | |||||
$scope.clusterMap = []; | |||||
$scope.remainingClientAddressList = []; | |||||
let tmpServerList = []; | |||||
let tmpClientList = []; | |||||
appClusterMachineList.forEach((e) => { | |||||
if (e.mode === CLUSTER_MODE_CLIENT) { | |||||
tmpClientList.push(e); | |||||
} else if (e.mode === CLUSTER_MODE_SERVER) { | |||||
tmpServerList.push(e); | |||||
} else { | |||||
$scope.remainingClientAddressList.push(generateMachineId(e)); | |||||
} | |||||
}); | |||||
tmpServerList.forEach((e) => { | |||||
let ip = e.ip; | |||||
let machineId = ip + '@' + e.commandPort; | |||||
let group = { | |||||
ip: ip, | |||||
machineId: machineId, | |||||
port: e.state.server.port, | |||||
clientSet: [], | |||||
namespaceSetStr: e.state.server.namespaceSetStr, | |||||
belongToApp: true, | |||||
}; | |||||
if (!tmpMap.has(ip)) { | |||||
tmpMap.set(ip, group); | |||||
} | |||||
}); | |||||
tmpClientList.forEach((e) => { | |||||
let ip = e.ip; | |||||
let machineId = ip + '@' + e.commandPort; | |||||
let targetServer = e.state.client.clientConfig.serverHost; | |||||
let targetPort = e.state.client.clientConfig.serverPort; | |||||
if (targetServer === undefined || targetServer === '' || | |||||
targetPort === undefined || targetPort <= 0) { | |||||
$scope.remainingClientAddressList.push(generateMachineId(e)); | |||||
return; | |||||
} | |||||
if (!tmpMap.has(targetServer)) { | |||||
let group = { | |||||
ip: targetServer, | |||||
machineId: targetServer, | |||||
port: targetPort, | |||||
clientSet: [machineId], | |||||
belongToApp: false, | |||||
}; | |||||
tmpMap.set(targetServer, group); | |||||
} else { | |||||
let g = tmpMap.get(targetServer); | |||||
g.clientSet.push(machineId); | |||||
} | |||||
}); | |||||
tmpMap.forEach((v) => { | |||||
if (v !== undefined) { | |||||
$scope.clusterMap.push(v); | |||||
} | |||||
}); | |||||
} | |||||
$scope.onCurrentServerChange = () => { | |||||
resetChosen(); | |||||
}; | |||||
$scope.remainingClientAddressList = []; | |||||
$scope.moveToServerGroup = () => { | |||||
let chosenServer = $scope.tmp.curChosenServer; | |||||
if (!chosenServer || !chosenServer.machineId) { | |||||
return; | |||||
} | |||||
$scope.tmp.curRemainingClientChosen.forEach(e => { | |||||
chosenServer.clientSet.push(e); | |||||
removeFromArr($scope.remainingClientAddressList, e); | |||||
}); | |||||
resetChosen(); | |||||
}; | |||||
$scope.moveToRemainingSharePool = () => { | |||||
$scope.tmp.curClientChosen.forEach(e => { | |||||
$scope.remainingClientAddressList.push(e); | |||||
removeFromArr($scope.tmp.curChosenServer.clientSet, e); | |||||
}); | |||||
resetChosen(); | |||||
}; | |||||
function parseIpFromMachineId(machineId) { | |||||
if (machineId.indexOf('@') === -1) { | |||||
return machineId; | |||||
} | |||||
let arr = machineId.split('@'); | |||||
return arr[0]; | |||||
} | |||||
$scope.addToServerList = () => { | |||||
let group; | |||||
$scope.tmp.curRemainingClientChosen.forEach(e => { | |||||
group = { | |||||
machineId: e, | |||||
ip: parseIpFromMachineId(e), | |||||
port: DEFAULT_CLUSTER_SERVER_PORT, | |||||
clientSet: [], | |||||
namespaceSetStr: 'default,' + $scope.app, | |||||
belongToApp: true, | |||||
}; | |||||
$scope.clusterMap.push(group); | |||||
removeFromArr($scope.remainingClientAddressList, e); | |||||
$scope.tmp.curChosenServer = group; | |||||
}); | |||||
resetChosen(); | |||||
}; | |||||
$scope.removeFromServerList = () => { | |||||
let chosenServer = $scope.tmp.curChosenServer; | |||||
if (!chosenServer || !chosenServer.machineId) { | |||||
return; | |||||
} | |||||
chosenServer.clientSet.forEach((e) => { | |||||
if (e !== undefined) { | |||||
$scope.remainingClientAddressList.push(e); | |||||
} | |||||
}); | |||||
if (chosenServer.belongToApp || chosenServer.machineId.indexOf('@') !== -1) { | |||||
$scope.remainingClientAddressList.push(chosenServer.machineId); | |||||
} else { | |||||
alert('提示:非本应用内机器将不会置回空闲列表中'); | |||||
} | |||||
removeFromArr($scope.clusterMap, chosenServer); | |||||
resetChosen(); | |||||
if ($scope.clusterMap.length > 0) { | |||||
$scope.tmp.curChosenServer = $scope.clusterMap[0]; | |||||
$scope.onCurrentServerChange(); | |||||
} else { | |||||
$scope.tmp.curChosenServer = {}; | |||||
} | |||||
}; | |||||
function retrieveClusterAppInfo() { | |||||
ClusterStateService.fetchClusterUniversalStateOfApp($scope.app).success(function (data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.appClusterMachineList = data.data; | |||||
$scope.appClusterMachineList.forEach(processAppSingleData); | |||||
applyClusterMap($scope.appClusterMachineList); | |||||
if ($scope.clusterMap.length > 0) { | |||||
$scope.tmp.curChosenServer = $scope.clusterMap[0]; | |||||
$scope.onCurrentServerChange(); | |||||
} | |||||
} else { | |||||
$scope.appClusterMachineList = {}; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
retrieveClusterAppInfo(); | |||||
$scope.saveAndApplyAssign = () => { | |||||
let ok = confirm('是否确认执行变更?'); | |||||
if (!ok) { | |||||
return; | |||||
} | |||||
let cm = $scope.clusterMap; | |||||
if (!cm) { | |||||
cm = []; | |||||
} | |||||
cm.forEach((e) => { | |||||
e.namespaceSet = convertStrToNamespaceSet(e.namespaceSetStr); | |||||
}); | |||||
cm.namespaceSet = convertStrToNamespaceSet(cm.namespaceSetStr); | |||||
let request = { | |||||
clusterMap: cm, | |||||
remainingList: $scope.remainingClientAddressList, | |||||
}; | |||||
ClusterStateService.applyClusterFullAssignOfApp($scope.app, request).success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
let failedServerSet = data.data.failedServerSet; | |||||
let failedClientSet = data.data.failedClientSet; | |||||
if (failedClientSet.length === 0 && failedServerSet.length === 0) { | |||||
alert('全部推送成功'); | |||||
} else { | |||||
alert('推送完毕。token server 失败列表:' + JSON.stringify(failedServerSet) + | |||||
'; token client 失败列表:' + JSON.stringify(failedClientSet)); | |||||
} | |||||
retrieveClusterAppInfo(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('推送失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error(() => { | |||||
alert('未知错误'); | |||||
}); | |||||
}; | |||||
}]); |
@@ -0,0 +1,543 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('SentinelClusterAppServerListController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | |||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | |||||
$scope.app = $stateParams.app; | |||||
const UNSUPPORTED_CODE = 4041; | |||||
const CLUSTER_MODE_CLIENT = 0; | |||||
const CLUSTER_MODE_SERVER = 1; | |||||
const DEFAULT_CLUSTER_SERVER_PORT = 18730; | |||||
const DEFAULT_NAMESPACE = 'default'; | |||||
const DEFAULT_MAX_ALLOWED_QPS = 20000; | |||||
// tmp for dialog temporary data. | |||||
$scope.tmp = { | |||||
curClientChosen: [], | |||||
curRemainingClientChosen: [], | |||||
curChosenServer: {}, | |||||
}; | |||||
$scope.remainingMachineList = []; | |||||
function convertSetToString(set) { | |||||
if (set === undefined) { | |||||
return ''; | |||||
} | |||||
if (set.length === 1 && set[0] === DEFAULT_NAMESPACE) { | |||||
return DEFAULT_NAMESPACE; | |||||
} | |||||
let s = ''; | |||||
for (let i = 0; i < set.length; i++) { | |||||
let ns = set[i]; | |||||
if (ns !== DEFAULT_NAMESPACE) { | |||||
s = s + ns; | |||||
if (i < set.length - 1) { | |||||
s = s + ','; | |||||
} | |||||
} | |||||
} | |||||
return s; | |||||
} | |||||
function convertStrToNamespaceSet(str) { | |||||
if (str === undefined || str === '') { | |||||
return []; | |||||
} | |||||
let arr = []; | |||||
let spliced = str.split(','); | |||||
spliced.forEach((v) => { | |||||
arr.push(v.trim()); | |||||
}); | |||||
return arr; | |||||
} | |||||
function processAppSingleData(data) { | |||||
if (data.state.server && data.state.server.namespaceSet) { | |||||
data.state.server.namespaceSetStr = convertSetToString(data.state.server.namespaceSet); | |||||
data.mode = data.state.stateInfo.mode; | |||||
} | |||||
} | |||||
function removeFromArr(arr, v) { | |||||
for (let i = 0; i < arr.length; i++) { | |||||
if (arr[i] === v) { | |||||
arr.splice(i, 1); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
function removeFromArrIf(arr, f) { | |||||
for (let i = 0; i < arr.length; i++) { | |||||
if (f(arr[i]) === true) { | |||||
arr.splice(i, 1); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
function resetAssignDialogChosen() { | |||||
$scope.tmp.curClientChosen = []; | |||||
$scope.tmp.curRemainingClientChosen = []; | |||||
} | |||||
function generateMachineId(e) { | |||||
return e.ip + '@' + e.commandPort; | |||||
} | |||||
function applyClusterMap(appClusterMachineList) { | |||||
if (!appClusterMachineList) { | |||||
return; | |||||
} | |||||
let tmpMap = new Map(); | |||||
$scope.clusterMap = []; | |||||
$scope.remainingMachineList = []; | |||||
let tmpServerList = []; | |||||
let tmpClientList = []; | |||||
appClusterMachineList.forEach((e) => { | |||||
if (e.mode === CLUSTER_MODE_CLIENT) { | |||||
tmpClientList.push(e); | |||||
} else if (e.mode === CLUSTER_MODE_SERVER) { | |||||
tmpServerList.push(e); | |||||
} else { | |||||
$scope.remainingMachineList.push(generateMachineId(e)); | |||||
} | |||||
}); | |||||
tmpServerList.forEach((e) => { | |||||
let ip = e.ip; | |||||
let machineId = ip + '@' + e.commandPort; | |||||
let group = { | |||||
ip: ip, | |||||
machineId: machineId, | |||||
port: e.state.server.port, | |||||
clientSet: [], | |||||
namespaceSetStr: e.state.server.namespaceSetStr, | |||||
maxAllowedQps: e.state.server.flow.maxAllowedQps, | |||||
belongToApp: true, | |||||
}; | |||||
if (!tmpMap.has(ip)) { | |||||
tmpMap.set(ip, group); | |||||
} | |||||
}); | |||||
tmpClientList.forEach((e) => { | |||||
let ip = e.ip; | |||||
let machineId = ip + '@' + e.commandPort; | |||||
let targetServer = e.state.client.clientConfig.serverHost; | |||||
let targetPort = e.state.client.clientConfig.serverPort; | |||||
if (targetServer === undefined || targetServer === '' || | |||||
targetPort === undefined || targetPort <= 0) { | |||||
$scope.remainingMachineList.push(generateMachineId(e)); | |||||
return; | |||||
} | |||||
if (!tmpMap.has(targetServer)) { | |||||
let group = { | |||||
ip: targetServer, | |||||
machineId: targetServer, | |||||
port: targetPort, | |||||
clientSet: [machineId], | |||||
belongToApp: false, | |||||
}; | |||||
tmpMap.set(targetServer, group); | |||||
} else { | |||||
let g = tmpMap.get(targetServer); | |||||
g.clientSet.push(machineId); | |||||
} | |||||
}); | |||||
tmpMap.forEach((v) => { | |||||
if (v !== undefined) { | |||||
$scope.clusterMap.push(v); | |||||
} | |||||
}); | |||||
} | |||||
$scope.notChosenServer = (id) => { | |||||
return id !== $scope.serverAssignDialogData.serverData.currentServer; | |||||
}; | |||||
$scope.onCurrentServerChange = () => { | |||||
resetAssignDialogChosen(); | |||||
}; | |||||
$scope.moveToServerGroup = () => { | |||||
$scope.tmp.curRemainingClientChosen.forEach(e => { | |||||
$scope.serverAssignDialogData.serverData.clientSet.push(e); | |||||
removeFromArr($scope.remainingMachineList, e); | |||||
}); | |||||
resetAssignDialogChosen(); | |||||
}; | |||||
$scope.moveToRemainingSharePool = () => { | |||||
$scope.tmp.curClientChosen.forEach(e => { | |||||
$scope.remainingMachineList.push(e); | |||||
removeFromArr($scope.serverAssignDialogData.serverData.clientSet, e); | |||||
}); | |||||
resetAssignDialogChosen(); | |||||
}; | |||||
function parseIpFromMachineId(machineId) { | |||||
if (machineId.indexOf('@') === -1) { | |||||
return machineId; | |||||
} | |||||
let arr = machineId.split('@'); | |||||
return arr[0]; | |||||
} | |||||
function retrieveClusterAssignInfoOfApp() { | |||||
ClusterStateService.fetchClusterUniversalStateOfApp($scope.app).success(function (data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.appClusterMachineList = data.data; | |||||
$scope.appClusterMachineList.forEach(processAppSingleData); | |||||
applyClusterMap($scope.appClusterMachineList); | |||||
} else { | |||||
$scope.appClusterMachineList = {}; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
$scope.newServerDialog = () => { | |||||
retrieveClusterAssignInfoOfApp(); | |||||
$scope.serverAssignDialogData = { | |||||
title: '新增 Token Server', | |||||
type: 'add', | |||||
confirmBtnText: '保存', | |||||
serverData: { | |||||
serverType: 0, | |||||
clientSet: [], | |||||
serverPort: DEFAULT_CLUSTER_SERVER_PORT, | |||||
maxAllowedQps: DEFAULT_MAX_ALLOWED_QPS, | |||||
} | |||||
}; | |||||
$scope.serverAssignDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/cluster/cluster-server-assign-dialog.html', | |||||
width: 1000, | |||||
overlay: true, | |||||
scope: $scope | |||||
}); | |||||
}; | |||||
$scope.modifyServerAssignConfig = (id) => { | |||||
ClusterStateService.fetchClusterUniversalStateOfApp($scope.app).success(function (data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.appClusterMachineList = data.data; | |||||
$scope.appClusterMachineList.forEach(processAppSingleData); | |||||
applyClusterMap($scope.appClusterMachineList); | |||||
let clusterMap = $scope.clusterMap; | |||||
let d; | |||||
for (let i = 0; i < clusterMap.length; i++) { | |||||
if (clusterMap[i].machineId === id) { | |||||
d = clusterMap[i]; | |||||
} | |||||
} | |||||
if (!d) { | |||||
alert('状态错误'); | |||||
return; | |||||
} | |||||
$scope.serverAssignDialogData = { | |||||
title: 'Token Server 分配编辑', | |||||
type: 'edit', | |||||
confirmBtnText: '保存', | |||||
serverData: { | |||||
currentServer: d.machineId, | |||||
belongToApp: true, | |||||
serverPort: d.port, | |||||
clientSet: d.clientSet, | |||||
} | |||||
}; | |||||
if (d.maxAllowedQps !== undefined) { | |||||
$scope.serverAssignDialogData.serverData.maxAllowedQps = d.maxAllowedQps; | |||||
} | |||||
$scope.serverAssignDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/cluster/cluster-server-assign-dialog.html', | |||||
width: 1000, | |||||
overlay: true, | |||||
scope: $scope | |||||
}); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
}; | |||||
function getRemainingMachineList() { | |||||
return $scope.remainingMachineList.filter((e) => $scope.notChosenServer(e)); | |||||
} | |||||
function doApplyNewSingleServerAssign() { | |||||
let ok = confirm('是否确认执行变更?'); | |||||
if (!ok) { | |||||
return; | |||||
} | |||||
let serverData = $scope.serverAssignDialogData.serverData; | |||||
let belongToApp = serverData.serverType == 0; // don't modify here! | |||||
let machineId = serverData.currentServer; | |||||
let request = { | |||||
clusterMap: { | |||||
machineId: machineId, | |||||
ip: parseIpFromMachineId(machineId), | |||||
port: serverData.serverPort, | |||||
clientSet: serverData.clientSet, | |||||
belongToApp: belongToApp, | |||||
maxAllowedQps: serverData.maxAllowedQps, | |||||
}, | |||||
remainingList: getRemainingMachineList(), | |||||
}; | |||||
ClusterStateService.applyClusterSingleServerAssignOfApp($scope.app, request).success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
let failedServerSet = data.data.failedServerSet; | |||||
let failedClientSet = data.data.failedClientSet; | |||||
if (failedClientSet.length === 0 && failedServerSet.length === 0) { | |||||
alert('全部推送成功'); | |||||
} else { | |||||
let failedSet = []; | |||||
if (failedServerSet) { | |||||
failedServerSet.forEach((e) => { | |||||
failedSet.push(e); | |||||
}); | |||||
} | |||||
if (failedClientSet) { | |||||
failedClientSet.forEach((e) => { | |||||
failedSet.push(e); | |||||
}); | |||||
} | |||||
alert('推送完毕。失败机器列表:' + JSON.stringify(failedSet)); | |||||
} | |||||
location.reload(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('推送失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error(() => { | |||||
alert('未知错误'); | |||||
}); | |||||
} | |||||
function doApplySingleServerAssignEdit() { | |||||
let ok = confirm('是否确认执行变更?'); | |||||
if (!ok) { | |||||
return; | |||||
} | |||||
let serverData = $scope.serverAssignDialogData.serverData; | |||||
let machineId = serverData.currentServer; | |||||
let request = { | |||||
clusterMap: { | |||||
machineId: machineId, | |||||
ip: parseIpFromMachineId(machineId), | |||||
port: serverData.serverPort, | |||||
clientSet: serverData.clientSet, | |||||
belongToApp: serverData.belongToApp, | |||||
}, | |||||
remainingList: $scope.remainingMachineList, | |||||
}; | |||||
if (serverData.maxAllowedQps !== undefined) { | |||||
request.clusterMap.maxAllowedQps = serverData.maxAllowedQps; | |||||
} | |||||
ClusterStateService.applyClusterSingleServerAssignOfApp($scope.app, request).success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
let failedServerSet = data.data.failedServerSet; | |||||
let failedClientSet = data.data.failedClientSet; | |||||
if (failedClientSet.length === 0 && failedServerSet.length === 0) { | |||||
alert('全部推送成功'); | |||||
} else { | |||||
let failedSet = []; | |||||
failedServerSet.forEach(failedSet.push); | |||||
failedClientSet.forEach(failedSet.push); | |||||
alert('推送完毕。失败机器列表:' + JSON.stringify(failedSet)); | |||||
} | |||||
location.reload(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('推送失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error(() => { | |||||
alert('未知错误'); | |||||
}); | |||||
} | |||||
$scope.saveAssignForDialog = () => { | |||||
if (!checkAssignDialogValid()) { | |||||
return; | |||||
} | |||||
if ($scope.serverAssignDialogData.type === 'add') { | |||||
doApplyNewSingleServerAssign(); | |||||
} else if ($scope.serverAssignDialogData.type === 'edit') { | |||||
doApplySingleServerAssignEdit(); | |||||
} else { | |||||
alert('未知的操作'); | |||||
} | |||||
}; | |||||
function checkAssignDialogValid() { | |||||
let serverData = $scope.serverAssignDialogData.serverData; | |||||
if (serverData.currentServer === undefined || serverData.currentServer === '') { | |||||
alert('请指定有效的 Token Server'); | |||||
return false; | |||||
} | |||||
if (serverData.serverPort === undefined || serverData.serverPort <= 0 || serverData.serverPort > 65535) { | |||||
alert('请输入合法的端口值'); | |||||
return false; | |||||
} | |||||
if (serverData.maxAllowedQps !== undefined && serverData.maxAllowedQps < 0) { | |||||
alert('请输入合法的最大允许 QPS'); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
$scope.viewConnectionDetail = (serverVO) => { | |||||
$scope.connectionDetailDialogData = { | |||||
serverData: serverVO | |||||
}; | |||||
$scope.connectionDetailDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/cluster/cluster-server-connection-detail-dialog.html', | |||||
width: 700, | |||||
overlay: true, | |||||
scope: $scope | |||||
}); | |||||
}; | |||||
function generateRequestLimitDataStr(limitData) { | |||||
if (limitData.length === 1 && limitData[0].namespace === DEFAULT_NAMESPACE) { | |||||
return 'default: ' + limitData[0].currentQps + ' / ' + limitData[0].maxAllowedQps; | |||||
} | |||||
for (let i = 0; i < limitData.length; i++) { | |||||
let crl = limitData[i]; | |||||
if (crl.namespace === $scope.app) { | |||||
return '' + crl.currentQps + ' / ' + crl.maxAllowedQps; | |||||
} | |||||
} | |||||
return '0'; | |||||
} | |||||
function processServerListData(serverVO) { | |||||
if (serverVO.state && serverVO.state.namespaceSet) { | |||||
serverVO.state.namespaceSetStr = convertSetToString(serverVO.state.namespaceSet); | |||||
} | |||||
if (serverVO.state && serverVO.state.requestLimitData) { | |||||
serverVO.state.requestLimitDataStr = generateRequestLimitDataStr(serverVO.state.requestLimitData); | |||||
} | |||||
} | |||||
$scope.generateConnectionSet = (data) => { | |||||
let connectionSet = data; | |||||
let s = ''; | |||||
if (connectionSet) { | |||||
s = s + '['; | |||||
for (let i = 0; i < connectionSet.length; i++) { | |||||
s = s + connectionSet[i].address; | |||||
if (i < connectionSet.length - 1) { | |||||
s = s + ', '; | |||||
} | |||||
} | |||||
s = s + ']'; | |||||
} else { | |||||
s = '[]'; | |||||
} | |||||
return s; | |||||
}; | |||||
function retrieveClusterServerInfo() { | |||||
ClusterStateService.fetchClusterServerStateOfApp($scope.app).success(function (data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.serverVOList = data.data; | |||||
$scope.serverVOList.forEach(processServerListData); | |||||
// if ($scope.serverVOList.length > 0) { | |||||
// $scope.tmp.curChosenServer = $scope.serverVOList[0]; | |||||
// $scope.onChosenServerChange(); | |||||
// } | |||||
} else { | |||||
$scope.serverVOList = {}; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
retrieveClusterServerInfo(); | |||||
let confirmUnbindServerDialog; | |||||
$scope.unbindServer = (id) => { | |||||
$scope.pendingUnbindIds = [id]; | |||||
$scope.confirmDialog = { | |||||
title: '移除 Token Server', | |||||
type: 'unbind_token_server', | |||||
attentionTitle: '请确认是否移除以下 Token Server(该 server 下的 client 也会解除分配)', | |||||
attention: id + '', | |||||
confirmBtnText: '移除', | |||||
}; | |||||
confirmUnbindServerDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/confirm-dialog.html', | |||||
scope: $scope, | |||||
overlay: true | |||||
}); | |||||
}; | |||||
function apiUnbindServerAssign(ids) { | |||||
ClusterStateService.applyClusterServerBatchUnbind($scope.app, ids).success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
let failedServerSet = data.data.failedServerSet; | |||||
let failedClientSet = data.data.failedClientSet; | |||||
if (failedClientSet.length === 0 && failedServerSet.length === 0) { | |||||
alert('成功'); | |||||
} else { | |||||
alert('操作推送完毕,部分失败机器列表:' + JSON.stringify(failedClientSet)); | |||||
} | |||||
location.reload(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('推送失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error(() => { | |||||
alert('未知错误'); | |||||
}); | |||||
// confirmUnbindServerDialog.close(); | |||||
} | |||||
// Confirm function for confirm dialog. | |||||
$scope.confirm = () => { | |||||
if ($scope.confirmDialog.type === 'unbind_token_server') { | |||||
apiUnbindServerAssign($scope.pendingUnbindIds); | |||||
} else { | |||||
console.error('Error dialog when unbinding token server'); | |||||
} | |||||
}; | |||||
}]); |
@@ -0,0 +1,283 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('SentinelClusterAppAssignManageController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | |||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | |||||
$scope.app = $stateParams.app; | |||||
const UNSUPPORTED_CODE = 4041; | |||||
const CLUSTER_MODE_CLIENT = 0; | |||||
const CLUSTER_MODE_SERVER = 1; | |||||
const DEFAULT_CLUSTER_SERVER_PORT = 18730; | |||||
$scope.tmp = { | |||||
curClientChosen: [], | |||||
curRemainingClientChosen: [], | |||||
curChosenServer: {}, | |||||
}; | |||||
function convertSetToString(set) { | |||||
if (set === undefined) { | |||||
return ''; | |||||
} | |||||
let s = ''; | |||||
for (let i = 0; i < set.length; i++) { | |||||
s = s + set[i]; | |||||
if (i < set.length - 1) { | |||||
s = s + ','; | |||||
} | |||||
} | |||||
return s; | |||||
} | |||||
function convertStrToNamespaceSet(str) { | |||||
if (str === undefined || str === '') { | |||||
return []; | |||||
} | |||||
let arr = []; | |||||
let spliced = str.split(','); | |||||
spliced.forEach((v) => { | |||||
arr.push(v.trim()); | |||||
}); | |||||
return arr; | |||||
} | |||||
function processAppSingleData(data) { | |||||
if (data.state.server && data.state.server.namespaceSet) { | |||||
data.state.server.namespaceSetStr = convertSetToString(data.state.server.namespaceSet); | |||||
data.mode = data.state.stateInfo.mode; | |||||
} | |||||
} | |||||
function removeFromArr(arr, v) { | |||||
for (let i = 0; i < arr.length; i++) { | |||||
if (arr[i] === v) { | |||||
arr.splice(i, 1); | |||||
break; | |||||
} | |||||
} | |||||
} | |||||
function resetChosen() { | |||||
$scope.tmp.curClientChosen = []; | |||||
$scope.tmp.curRemainingClientChosen = []; | |||||
} | |||||
function generateMachineId(e) { | |||||
return e.ip + '@' + e.commandPort; | |||||
} | |||||
function applyClusterMap(appClusterMachineList) { | |||||
if (!appClusterMachineList) { | |||||
return; | |||||
} | |||||
let tmpMap = new Map(); | |||||
$scope.clusterMap = []; | |||||
$scope.remainingClientAddressList = []; | |||||
let tmpServerList = []; | |||||
let tmpClientList = []; | |||||
appClusterMachineList.forEach((e) => { | |||||
if (e.mode === CLUSTER_MODE_CLIENT) { | |||||
tmpClientList.push(e); | |||||
} else if (e.mode === CLUSTER_MODE_SERVER) { | |||||
tmpServerList.push(e); | |||||
} else { | |||||
$scope.remainingClientAddressList.push(generateMachineId(e)); | |||||
} | |||||
}); | |||||
tmpServerList.forEach((e) => { | |||||
let ip = e.ip; | |||||
let machineId = ip + '@' + e.commandPort; | |||||
let group = { | |||||
ip: ip, | |||||
machineId: machineId, | |||||
port: e.state.server.port, | |||||
clientSet: [], | |||||
namespaceSetStr: e.state.server.namespaceSetStr, | |||||
belongToApp: true, | |||||
}; | |||||
if (!tmpMap.has(ip)) { | |||||
tmpMap.set(ip, group); | |||||
} | |||||
}); | |||||
tmpClientList.forEach((e) => { | |||||
let ip = e.ip; | |||||
let machineId = ip + '@' + e.commandPort; | |||||
let targetServer = e.state.client.clientConfig.serverHost; | |||||
let targetPort = e.state.client.clientConfig.serverPort; | |||||
if (targetServer === undefined || targetServer === '' || | |||||
targetPort === undefined || targetPort <= 0) { | |||||
$scope.remainingClientAddressList.push(generateMachineId(e)); | |||||
return; | |||||
} | |||||
if (!tmpMap.has(targetServer)) { | |||||
let group = { | |||||
ip: targetServer, | |||||
machineId: targetServer, | |||||
port: targetPort, | |||||
clientSet: [machineId], | |||||
belongToApp: false, | |||||
}; | |||||
tmpMap.set(targetServer, group); | |||||
} else { | |||||
let g = tmpMap.get(targetServer); | |||||
g.clientSet.push(machineId); | |||||
} | |||||
}); | |||||
tmpMap.forEach((v) => { | |||||
if (v !== undefined) { | |||||
$scope.clusterMap.push(v); | |||||
} | |||||
}); | |||||
} | |||||
$scope.onCurrentServerChange = () => { | |||||
resetChosen(); | |||||
}; | |||||
$scope.remainingClientAddressList = []; | |||||
$scope.moveToServerGroup = () => { | |||||
let chosenServer = $scope.tmp.curChosenServer; | |||||
if (!chosenServer || !chosenServer.machineId) { | |||||
return; | |||||
} | |||||
$scope.tmp.curRemainingClientChosen.forEach(e => { | |||||
chosenServer.clientSet.push(e); | |||||
removeFromArr($scope.remainingClientAddressList, e); | |||||
}); | |||||
resetChosen(); | |||||
}; | |||||
$scope.moveToRemainingSharePool = () => { | |||||
$scope.tmp.curClientChosen.forEach(e => { | |||||
$scope.remainingClientAddressList.push(e); | |||||
removeFromArr($scope.tmp.curChosenServer.clientSet, e); | |||||
}); | |||||
resetChosen(); | |||||
}; | |||||
function parseIpFromMachineId(machineId) { | |||||
if (machineId.indexOf('@') === -1) { | |||||
return machineId; | |||||
} | |||||
let arr = machineId.split('@'); | |||||
return arr[0]; | |||||
} | |||||
$scope.addToServerList = () => { | |||||
let group; | |||||
$scope.tmp.curRemainingClientChosen.forEach(e => { | |||||
group = { | |||||
machineId: e, | |||||
ip: parseIpFromMachineId(e), | |||||
port: DEFAULT_CLUSTER_SERVER_PORT, | |||||
clientSet: [], | |||||
namespaceSetStr: 'default,' + $scope.app, | |||||
belongToApp: true, | |||||
}; | |||||
$scope.clusterMap.push(group); | |||||
removeFromArr($scope.remainingClientAddressList, e); | |||||
$scope.tmp.curChosenServer = group; | |||||
}); | |||||
resetChosen(); | |||||
}; | |||||
$scope.removeFromServerList = () => { | |||||
let chosenServer = $scope.tmp.curChosenServer; | |||||
if (!chosenServer || !chosenServer.machineId) { | |||||
return; | |||||
} | |||||
chosenServer.clientSet.forEach((e) => { | |||||
if (e !== undefined) { | |||||
$scope.remainingClientAddressList.push(e); | |||||
} | |||||
}); | |||||
if (chosenServer.belongToApp || chosenServer.machineId.indexOf('@') !== -1) { | |||||
$scope.remainingClientAddressList.push(chosenServer.machineId); | |||||
} else { | |||||
alert('提示:非本应用内机器将不会置回空闲列表中'); | |||||
} | |||||
removeFromArr($scope.clusterMap, chosenServer); | |||||
resetChosen(); | |||||
if ($scope.clusterMap.length > 0) { | |||||
$scope.tmp.curChosenServer = $scope.clusterMap[0]; | |||||
$scope.onCurrentServerChange(); | |||||
} else { | |||||
$scope.tmp.curChosenServer = {}; | |||||
} | |||||
}; | |||||
function retrieveClusterAppInfo() { | |||||
ClusterStateService.fetchClusterUniversalStateOfApp($scope.app).success(function (data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.appClusterMachineList = data.data; | |||||
$scope.appClusterMachineList.forEach(processAppSingleData); | |||||
applyClusterMap($scope.appClusterMachineList); | |||||
if ($scope.clusterMap.length > 0) { | |||||
$scope.tmp.curChosenServer = $scope.clusterMap[0]; | |||||
$scope.onCurrentServerChange(); | |||||
} | |||||
} else { | |||||
$scope.appClusterMachineList = {}; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
retrieveClusterAppInfo(); | |||||
$scope.saveAndApplyAssign = () => { | |||||
let ok = confirm('是否确认执行变更?'); | |||||
if (!ok) { | |||||
return; | |||||
} | |||||
let cm = $scope.clusterMap; | |||||
if (!cm) { | |||||
cm = []; | |||||
} | |||||
cm.forEach((e) => { | |||||
e.namespaceSet = convertStrToNamespaceSet(e.namespaceSetStr); | |||||
}); | |||||
cm.namespaceSet = convertStrToNamespaceSet(cm.namespaceSetStr); | |||||
let request = { | |||||
clusterMap: cm, | |||||
remainingList: $scope.remainingClientAddressList, | |||||
}; | |||||
ClusterStateService.applyClusterFullAssignOfApp($scope.app, request).success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
let failedServerSet = data.data.failedServerSet; | |||||
let failedClientSet = data.data.failedClientSet; | |||||
if (failedClientSet.length === 0 && failedServerSet.length === 0) { | |||||
alert('全部推送成功'); | |||||
} else { | |||||
alert('推送完毕。token server 失败列表:' + JSON.stringify(failedServerSet) + | |||||
'; token client 失败列表:' + JSON.stringify(failedClientSet)); | |||||
} | |||||
retrieveClusterAppInfo(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('推送失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error(() => { | |||||
alert('未知错误'); | |||||
}); | |||||
}; | |||||
}]); |
@@ -0,0 +1,97 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('SentinelClusterAppServerMonitorController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | |||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | |||||
$scope.app = $stateParams.app; | |||||
const UNSUPPORTED_CODE = 4041; | |||||
const CLUSTER_MODE_SERVER = 1; | |||||
$scope.tmp = { | |||||
curChosenServer: {}, | |||||
}; | |||||
function convertSetToString(set) { | |||||
if (set === undefined) { | |||||
return ''; | |||||
} | |||||
let s = ''; | |||||
for (let i = 0; i < set.length; i++) { | |||||
s = s + set[i]; | |||||
if (i < set.length - 1) { | |||||
s = s + ','; | |||||
} | |||||
} | |||||
return s; | |||||
} | |||||
function processServerData(serverVO) { | |||||
if (serverVO.state && serverVO.state.namespaceSet) { | |||||
serverVO.state.namespaceSetStr = convertSetToString(serverVO.state.namespaceSet); | |||||
} | |||||
} | |||||
$scope.generateConnectionSet = (data) => { | |||||
let connectionSet = data; | |||||
let s = ''; | |||||
if (connectionSet) { | |||||
s = s + '['; | |||||
for (let i = 0; i < connectionSet.length; i++) { | |||||
s = s + connectionSet[i].address; | |||||
if (i < connectionSet.length - 1) { | |||||
s = s + ', '; | |||||
} | |||||
} | |||||
s = s + ']'; | |||||
} else { | |||||
s = '[]'; | |||||
} | |||||
return s; | |||||
}; | |||||
$scope.onChosenServerChange = () => { | |||||
}; | |||||
function retrieveClusterServerInfo() { | |||||
ClusterStateService.fetchClusterServerStateOfApp($scope.app).success(function (data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.serverVOList = data.data; | |||||
$scope.serverVOList.forEach(processServerData); | |||||
if ($scope.serverVOList.length > 0) { | |||||
$scope.tmp.curChosenServer = $scope.serverVOList[0]; | |||||
$scope.onChosenServerChange(); | |||||
} | |||||
} else { | |||||
$scope.serverVOList = {}; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}).error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
retrieveClusterServerInfo(); | |||||
$scope.macsInputConfig = { | |||||
searchField: ['text', 'value'], | |||||
persist: true, | |||||
create: false, | |||||
maxItems: 1, | |||||
render: { | |||||
item: function (data, escape) { | |||||
return '<div>' + escape(data.text) + '</div>'; | |||||
} | |||||
}, | |||||
onChange: function (value, oldValue) { | |||||
$scope.macInputModel = value; | |||||
} | |||||
}; | |||||
}]); |
@@ -0,0 +1,121 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | |||||
app.controller('SentinelClusterAppTokenClientListController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | |||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | |||||
$scope.app = $stateParams.app; | |||||
const UNSUPPORTED_CODE = 4041; | |||||
const CLUSTER_MODE_CLIENT = 0; | |||||
const CLUSTER_MODE_SERVER = 1; | |||||
function processClientData(clientVO) { | |||||
} | |||||
$scope.modifyClientConfigDialog = (clientVO) => { | |||||
if (!clientVO) { | |||||
return; | |||||
} | |||||
$scope.ccDialogData = { | |||||
ip: clientVO.ip, | |||||
commandPort: clientVO.commandPort, | |||||
clientId: clientVO.id, | |||||
serverHost: clientVO.state.clientConfig.serverHost, | |||||
serverPort: clientVO.state.clientConfig.serverPort, | |||||
requestTimeout: clientVO.state.clientConfig.requestTimeout, | |||||
}; | |||||
$scope.ccDialog = ngDialog.open({ | |||||
template: '/app/views/dialog/cluster/cluster-client-config-dialog.html', | |||||
width: 700, | |||||
overlay: true, | |||||
scope: $scope | |||||
}); | |||||
}; | |||||
function checkValidClientConfig(config) { | |||||
if (!config.serverHost || config.serverHost.trim() == '') { | |||||
alert('请输入有效的 Token Server IP'); | |||||
return false; | |||||
} | |||||
if (config.serverPort === undefined || config.serverPort <= 0 || config.serverPort > 65535) { | |||||
alert('请输入有效的 Token Server 端口'); | |||||
return false; | |||||
} | |||||
if (config.requestTimeout === undefined || config.requestTimeout <= 0) { | |||||
alert('请输入有效的请求超时时长'); | |||||
return false; | |||||
} | |||||
return true; | |||||
} | |||||
$scope.doModifyClientConfig = () => { | |||||
if (!checkValidClientConfig($scope.ccDialogData)) { | |||||
return; | |||||
} | |||||
let id = $scope.ccDialogData.id; | |||||
let request = { | |||||
app: $scope.app, | |||||
ip: $scope.ccDialogData.ip, | |||||
port: $scope.ccDialogData.commandPort, | |||||
mode: CLUSTER_MODE_CLIENT, | |||||
clientConfig: { | |||||
serverHost: $scope.ccDialogData.serverHost, | |||||
serverPort: $scope.ccDialogData.serverPort, | |||||
requestTimeout: $scope.ccDialogData.requestTimeout, | |||||
} | |||||
}; | |||||
ClusterStateService.modifyClusterConfig(request).success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
alert('修改 Token Client 配置成功'); | |||||
window.location.reload(); | |||||
} else { | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
alert('机器 ' + id + ' 的 Sentinel 没有引入集群限流客户端,请升级至 1.4.0 以上版本并引入相关依赖。'); | |||||
} else { | |||||
alert('修改失败:' + data.msg); | |||||
} | |||||
} | |||||
}).error((data, header, config, status) => { | |||||
alert('未知错误'); | |||||
}); | |||||
}; | |||||
function retrieveClusterTokenClientInfo() { | |||||
ClusterStateService.fetchClusterClientStateOfApp($scope.app) | |||||
.success((data) => { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | |||||
$scope.clientVOList = data.data; | |||||
$scope.clientVOList.forEach(processClientData); | |||||
} else { | |||||
$scope.clientVOList = []; | |||||
if (data.code === UNSUPPORTED_CODE) { | |||||
$scope.loadError = {message: '该应用的 Sentinel 客户端不支持集群限流,请升级至 1.4.0 以上版本并引入相关依赖。'} | |||||
} else { | |||||
$scope.loadError = {message: data.msg}; | |||||
} | |||||
} | |||||
}) | |||||
.error(() => { | |||||
$scope.loadError = {message: '未知错误'}; | |||||
}); | |||||
} | |||||
retrieveClusterTokenClientInfo(); | |||||
$scope.macsInputConfig = { | |||||
searchField: ['text', 'value'], | |||||
persist: true, | |||||
create: false, | |||||
maxItems: 1, | |||||
render: { | |||||
item: function (data, escape) { | |||||
return '<div>' + escape(data.text) + '</div>'; | |||||
} | |||||
}, | |||||
onChange: function (value, oldValue) { | |||||
$scope.macInputModel = value; | |||||
} | |||||
}; | |||||
}]); |
@@ -1,6 +1,6 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog', | |||||
app.controller('SentinelClusterSingleController', ['$scope', '$stateParams', 'ngDialog', | |||||
'MachineService', 'ClusterStateService', | 'MachineService', 'ClusterStateService', | ||||
function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | function ($scope, $stateParams, ngDialog, MachineService, ClusterStateService) { | ||||
$scope.app = $stateParams.app; | $scope.app = $stateParams.app; | ||||
@@ -39,7 +39,7 @@ app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog | |||||
} | } | ||||
function convertStrToNamespaceSet(str) { | function convertStrToNamespaceSet(str) { | ||||
if (str === undefined || str == '') { | |||||
if (str === undefined || str === '') { | |||||
return []; | return []; | ||||
} | } | ||||
let arr = []; | let arr = []; | ||||
@@ -51,11 +51,11 @@ app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog | |||||
} | } | ||||
function fetchMachineClusterState() { | function fetchMachineClusterState() { | ||||
if (!$scope.macInputModel) { | |||||
if (!$scope.macInputModel || $scope.macInputModel === '') { | |||||
return; | return; | ||||
} | } | ||||
let mac = $scope.macInputModel.split(':'); | let mac = $scope.macInputModel.split(':'); | ||||
ClusterStateService.fetchClusterUniversalState($scope.app, mac[0], mac[1]).success(function (data) { | |||||
ClusterStateService.fetchClusterUniversalStateSingle($scope.app, mac[0], mac[1]).success(function (data) { | |||||
if (data.code == 0 && data.data) { | if (data.code == 0 && data.data) { | ||||
$scope.loadError = undefined; | $scope.loadError = undefined; | ||||
$scope.stateVO = data.data; | $scope.stateVO = data.data; | ||||
@@ -144,6 +144,11 @@ app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog | |||||
alert('请输入有效的 Token Server 端口'); | alert('请输入有效的 Token Server 端口'); | ||||
return false; | return false; | ||||
} | } | ||||
let flowConfig = stateVO.server.flow; | |||||
if (flowConfig.maxAllowedQps === undefined || flowConfig.maxAllowedQps < 0) { | |||||
alert('请输入有效的最大允许 QPS'); | |||||
return false; | |||||
} | |||||
// if (transportConfig.idleSeconds === undefined || transportConfig.idleSeconds <= 0) { | // if (transportConfig.idleSeconds === undefined || transportConfig.idleSeconds <= 0) { | ||||
// alert('请输入有效的连接清理时长 (idleSeconds)'); | // alert('请输入有效的连接清理时长 (idleSeconds)'); | ||||
// return false; | // return false; | ||||
@@ -205,19 +210,21 @@ app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog | |||||
function queryAppMachines() { | function queryAppMachines() { | ||||
MachineService.getAppMachines($scope.app).success( | MachineService.getAppMachines($scope.app).success( | ||||
function (data) { | function (data) { | ||||
if (data.code == 0) { | |||||
if (data.code === 0) { | |||||
// $scope.machines = data.data; | // $scope.machines = data.data; | ||||
if (data.data) { | if (data.data) { | ||||
$scope.machines = []; | $scope.machines = []; | ||||
$scope.macsInputOptionsOrigin = []; | |||||
$scope.macsInputOptions = []; | $scope.macsInputOptions = []; | ||||
data.data.forEach(function (item) { | data.data.forEach(function (item) { | ||||
if (item.health) { | if (item.health) { | ||||
$scope.macsInputOptions.push({ | |||||
$scope.macsInputOptionsOrigin.push({ | |||||
text: item.ip + ':' + item.port, | text: item.ip + ':' + item.port, | ||||
value: item.ip + ':' + item.port | value: item.ip + ':' + item.port | ||||
}); | }); | ||||
} | } | ||||
}); | }); | ||||
$scope.macsInputOptions = $scope.macsInputOptionsOrigin; | |||||
} | } | ||||
if ($scope.macsInputOptions.length > 0) { | if ($scope.macsInputOptions.length > 0) { | ||||
$scope.macInputModel = $scope.macsInputOptions[0].value; | $scope.macInputModel = $scope.macsInputOptions[0].value; | ||||
@@ -227,11 +234,29 @@ app.controller('SentinelClusterController', ['$scope', '$stateParams', 'ngDialog | |||||
} | } | ||||
} | } | ||||
); | ); | ||||
}; | |||||
} | |||||
queryAppMachines(); | |||||
$scope.$watch('searchKey', function () { | |||||
if (!$scope.macsInputOptions) { | |||||
return; | |||||
} | |||||
if ($scope.searchKey) { | |||||
$scope.macsInputOptions = $scope.macsInputOptionsOrigin | |||||
.filter((e) => e.value.indexOf($scope.searchKey) !== -1); | |||||
} else { | |||||
$scope.macsInputOptions = $scope.macsInputOptionsOrigin; | |||||
} | |||||
if ($scope.macsInputOptions.length > 0) { | |||||
$scope.macInputModel = $scope.macsInputOptions[0].value; | |||||
} else { | |||||
$scope.macInputModel = ''; | |||||
} | |||||
}); | |||||
$scope.$watch('macInputModel', function () { | $scope.$watch('macInputModel', function () { | ||||
if ($scope.macInputModel) { | if ($scope.macInputModel) { | ||||
fetchMachineClusterState(); | fetchMachineClusterState(); | ||||
} | } | ||||
}); | }); | ||||
queryAppMachines(); | |||||
}]); | }]); |
@@ -1,6 +1,6 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.controller('FlowController', ['$scope', '$stateParams', 'FlowServiceV2', 'ngDialog', | |||||
app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', 'ngDialog', | |||||
'MachineService', | 'MachineService', | ||||
function ($scope, $stateParams, FlowService, ngDialog, | function ($scope, $stateParams, FlowService, ngDialog, | ||||
MachineService) { | MachineService) { | ||||
@@ -27,6 +27,19 @@ app.controller('FlowController', ['$scope', '$stateParams', 'FlowServiceV2', 'ng | |||||
} | } | ||||
}; | }; | ||||
$scope.generateThresholdTypeShow = (rule) => { | |||||
if (!rule.clusterMode) { | |||||
return '单机'; | |||||
} | |||||
if (rule.clusterConfig.thresholdType === 0) { | |||||
return '集群均摊'; | |||||
} else if (rule.clusterConfig.thresholdType === 1) { | |||||
return '集群总体'; | |||||
} else { | |||||
return '集群'; | |||||
} | |||||
}; | |||||
getMachineRules(); | getMachineRules(); | ||||
function getMachineRules() { | function getMachineRules() { | ||||
if (!$scope.macInputModel) { | if (!$scope.macInputModel) { |
@@ -1,6 +1,6 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', 'ngDialog', | |||||
app.controller('FlowControllerV2', ['$scope', '$stateParams', 'FlowServiceV2', 'ngDialog', | |||||
'MachineService', | 'MachineService', | ||||
function ($scope, $stateParams, FlowService, ngDialog, | function ($scope, $stateParams, FlowService, ngDialog, | ||||
MachineService) { | MachineService) { | ||||
@@ -27,6 +27,19 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', ' | |||||
} | } | ||||
}; | }; | ||||
$scope.generateThresholdTypeShow = (rule) => { | |||||
if (!rule.clusterMode) { | |||||
return '单机'; | |||||
} | |||||
if (rule.clusterConfig.thresholdType === 0) { | |||||
return '集群均摊'; | |||||
} else if (rule.clusterConfig.thresholdType === 1) { | |||||
return '集群总体'; | |||||
} else { | |||||
return '集群'; | |||||
} | |||||
}; | |||||
getMachineRules(); | getMachineRules(); | ||||
function getMachineRules() { | function getMachineRules() { | ||||
if (!$scope.macInputModel) { | if (!$scope.macInputModel) { | ||||
@@ -72,7 +85,11 @@ app.controller('FlowControllerV1', ['$scope', '$stateParams', 'FlowServiceV1', ' | |||||
app: $scope.app, | app: $scope.app, | ||||
ip: mac[0], | ip: mac[0], | ||||
port: mac[1], | port: mac[1], | ||||
limitApp: 'default' | |||||
limitApp: 'default', | |||||
clusterMode: false, | |||||
clusterConfig: { | |||||
thresholdType: 0 | |||||
} | |||||
}; | }; | ||||
$scope.flowRuleDialog = { | $scope.flowRuleDialog = { | ||||
title: '新增流控规则', | title: '新增流控规则', |
@@ -1,7 +1,7 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | ||||
'ngDialog', 'FlowServiceV2', 'DegradeService', 'AuthorityRuleService', 'ParamFlowService', 'MachineService', | |||||
'ngDialog', 'FlowServiceV1', 'DegradeService', 'AuthorityRuleService', 'ParamFlowService', 'MachineService', | |||||
'$interval', '$location', '$timeout', | '$interval', '$location', '$timeout', | ||||
function ($scope, $stateParams, IdentityService, ngDialog, | function ($scope, $stateParams, IdentityService, ngDialog, | ||||
FlowService, DegradeService, AuthorityRuleService, ParamFlowService, MachineService, $interval, $location, $timeout) { | FlowService, DegradeService, AuthorityRuleService, ParamFlowService, MachineService, $interval, $location, $timeout) { | ||||
@@ -52,6 +52,10 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||||
controlBehavior: 0, | controlBehavior: 0, | ||||
resource: resource, | resource: resource, | ||||
limitApp: 'default', | limitApp: 'default', | ||||
clusterMode: false, | |||||
clusterConfig: { | |||||
thresholdType: 0 | |||||
}, | |||||
app: $scope.app, | app: $scope.app, | ||||
ip: mac[0], | ip: mac[0], | ||||
port: mac[1] | port: mac[1] | ||||
@@ -89,13 +93,15 @@ app.controller('IdentityCtl', ['$scope', '$stateParams', 'IdentityService', | |||||
return; | return; | ||||
} | } | ||||
FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) { | FlowService.newRule(flowRuleDialogScope.currentRule).success(function (data) { | ||||
if (data.code == 0) { | |||||
if (data.code === 0) { | |||||
flowRuleDialog.close(); | flowRuleDialog.close(); | ||||
let url = '/dashboard/flow/' + $scope.app; | let url = '/dashboard/flow/' + $scope.app; | ||||
$location.path(url); | $location.path(url); | ||||
} else { | } else { | ||||
alert('失败!'); | alert('失败!'); | ||||
} | } | ||||
}).error((data, header, config, status) => { | |||||
alert('未知错误'); | |||||
}); | }); | ||||
} | } | ||||
@@ -105,7 +105,7 @@ angular.module('sentinelDashboardApp').controller('ParamFlowController', ['$scop | |||||
let mac = $scope.macInputModel.split(':'); | let mac = $scope.macInputModel.split(':'); | ||||
ParamFlowService.queryMachineRules($scope.app, mac[0], mac[1]) | ParamFlowService.queryMachineRules($scope.app, mac[0], mac[1]) | ||||
.success(function (data) { | .success(function (data) { | ||||
if (data.code == 0 && data.data) { | |||||
if (data.code === 0 && data.data) { | |||||
$scope.loadError = undefined; | $scope.loadError = undefined; | ||||
$scope.rules = data.data; | $scope.rules = data.data; | ||||
$scope.rulesPageConfig.totalCount = $scope.rules.length; | $scope.rulesPageConfig.totalCount = $scope.rules.length; | ||||
@@ -157,6 +157,10 @@ angular.module('sentinelDashboardApp').controller('ParamFlowController', ['$scop | |||||
paramFlowItemList: [], | paramFlowItemList: [], | ||||
count: 0, | count: 0, | ||||
limitApp: 'default', | limitApp: 'default', | ||||
clusterMode: false, | |||||
clusterConfig: { | |||||
thresholdType: 0 | |||||
} | |||||
} | } | ||||
}; | }; | ||||
$scope.paramFlowRuleDialog = { | $scope.paramFlowRuleDialog = { | ||||
@@ -57,8 +57,8 @@ | |||||
<i class="glyphicon glyphicon-check"></i> 授权规则</a> | <i class="glyphicon glyphicon-check"></i> 授权规则</a> | ||||
</li> | </li> | ||||
<li ui-sref-active="active"> | <li ui-sref-active="active"> | ||||
<a ui-sref="dashboard.clusterAll({app: entry.app})"> | |||||
<i class="glyphicon glyphicon-cloud"></i> 集群限流</a> | |||||
<a ui-sref="dashboard.clusterAppServerList({app: entry.app})"> | |||||
<i class="glyphicon glyphicon-cloud"></i> 集群流控</a> | |||||
</li> | </li> | ||||
<li ui-sref-active="active"> | <li ui-sref-active="active"> | ||||
<a ui-sref="dashboard.machine({app: entry.app})"> | <a ui-sref="dashboard.machine({app: entry.app})"> | ||||
@@ -1,28 +1,73 @@ | |||||
/** | /** | ||||
* Parameter flow control service. | |||||
* Cluster state control service. | |||||
* | * | ||||
* @author Eric Zhao | * @author Eric Zhao | ||||
*/ | */ | ||||
angular.module('sentinelDashboardApp').service('ClusterStateService', ['$http', function ($http) { | angular.module('sentinelDashboardApp').service('ClusterStateService', ['$http', function ($http) { | ||||
this.fetchClusterUniversalState = function(app, ip, port) { | |||||
this.fetchClusterUniversalStateSingle = function(app, ip, port) { | |||||
var param = { | var param = { | ||||
app: app, | app: app, | ||||
ip: ip, | ip: ip, | ||||
port: port | port: port | ||||
}; | }; | ||||
return $http({ | return $http({ | ||||
url: '/cluster/state', | |||||
url: '/cluster/state_single', | |||||
params: param, | params: param, | ||||
method: 'GET' | method: 'GET' | ||||
}); | }); | ||||
}; | }; | ||||
this.fetchClusterUniversalStateOfApp = function(app) { | |||||
return $http({ | |||||
url: '/cluster/state/' + app, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.fetchClusterServerStateOfApp = function(app) { | |||||
return $http({ | |||||
url: '/cluster/server_state/' + app, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.fetchClusterClientStateOfApp = function(app) { | |||||
return $http({ | |||||
url: '/cluster/client_state/' + app, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.modifyClusterConfig = function(config) { | this.modifyClusterConfig = function(config) { | ||||
return $http({ | return $http({ | ||||
url: '/cluster/config/modify', | |||||
url: '/cluster/config/modify_single', | |||||
data: config, | data: config, | ||||
method: 'POST' | method: 'POST' | ||||
}); | }); | ||||
}; | }; | ||||
this.applyClusterFullAssignOfApp = function(app, clusterMap) { | |||||
return $http({ | |||||
url: '/cluster/assign/all_server/' + app, | |||||
data: clusterMap, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
this.applyClusterSingleServerAssignOfApp = function(app, request) { | |||||
return $http({ | |||||
url: '/cluster/assign/single_server/' + app, | |||||
data: request, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
this.applyClusterServerBatchUnbind = function(app, machineSet) { | |||||
return $http({ | |||||
url: '/cluster/assign/unbind_server/' + app, | |||||
data: machineSet, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
}]); | }]); |
@@ -1,76 +1,76 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.service('FlowServiceV1', ['$http', function ($http) { | app.service('FlowServiceV1', ['$http', function ($http) { | ||||
this.queryMachineRules = function (app, ip, port) { | |||||
var param = { | |||||
app: app, | |||||
ip: ip, | |||||
port: port | |||||
this.queryMachineRules = function (app, ip, port) { | |||||
var param = { | |||||
app: app, | |||||
ip: ip, | |||||
port: port | |||||
}; | |||||
return $http({ | |||||
url: '/v1/flow/rules', | |||||
params: param, | |||||
method: 'GET' | |||||
}); | |||||
}; | }; | ||||
return $http({ | |||||
url: '/v1/flow/rules', | |||||
params: param, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.newRule = function (rule) { | |||||
var param = { | |||||
resource: rule.resource, | |||||
limitApp: rule.limitApp, | |||||
grade: rule.grade, | |||||
count: rule.count, | |||||
strategy: rule.strategy, | |||||
refResource: rule.refResource, | |||||
controlBehavior: rule.controlBehavior, | |||||
warmUpPeriodSec: rule.warmUpPeriodSec, | |||||
maxQueueingTimeMs: rule.maxQueueingTimeMs, | |||||
app: rule.app, | |||||
ip: rule.ip, | |||||
port: rule.port | |||||
this.newRule = function (rule) { | |||||
var param = { | |||||
resource: rule.resource, | |||||
limitApp: rule.limitApp, | |||||
grade: rule.grade, | |||||
count: rule.count, | |||||
strategy: rule.strategy, | |||||
refResource: rule.refResource, | |||||
controlBehavior: rule.controlBehavior, | |||||
warmUpPeriodSec: rule.warmUpPeriodSec, | |||||
maxQueueingTimeMs: rule.maxQueueingTimeMs, | |||||
app: rule.app, | |||||
ip: rule.ip, | |||||
port: rule.port | |||||
}; | |||||
return $http({ | |||||
url: '/v1/flow/rule', | |||||
data: rule, | |||||
method: 'POST' | |||||
}); | |||||
}; | }; | ||||
return $http({ | |||||
url: '/v1/flow/rule', | |||||
data: rule, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
this.saveRule = function (rule) { | |||||
var param = { | |||||
id: rule.id, | |||||
resource: rule.resource, | |||||
limitApp: rule.limitApp, | |||||
grade: rule.grade, | |||||
count: rule.count, | |||||
strategy: rule.strategy, | |||||
refResource: rule.refResource, | |||||
controlBehavior: rule.controlBehavior, | |||||
warmUpPeriodSec: rule.warmUpPeriodSec, | |||||
maxQueueingTimeMs: rule.maxQueueingTimeMs, | |||||
}; | |||||
this.saveRule = function (rule) { | |||||
var param = { | |||||
id: rule.id, | |||||
resource: rule.resource, | |||||
limitApp: rule.limitApp, | |||||
grade: rule.grade, | |||||
count: rule.count, | |||||
strategy: rule.strategy, | |||||
refResource: rule.refResource, | |||||
controlBehavior: rule.controlBehavior, | |||||
warmUpPeriodSec: rule.warmUpPeriodSec, | |||||
maxQueueingTimeMs: rule.maxQueueingTimeMs, | |||||
return $http({ | |||||
url: '/v1/flow/save.json', | |||||
params: param, | |||||
method: 'PUT' | |||||
}); | |||||
}; | }; | ||||
return $http({ | |||||
url: '/v1/flow/save.json', | |||||
params: param, | |||||
method: 'PUT' | |||||
}); | |||||
}; | |||||
this.deleteRule = function (rule) { | |||||
var param = { | |||||
id: rule.id, | |||||
app: rule.app | |||||
}; | |||||
this.deleteRule = function (rule) { | |||||
var param = { | |||||
id: rule.id, | |||||
app: rule.app | |||||
return $http({ | |||||
url: '/v1/flow/delete.json', | |||||
params: param, | |||||
method: 'DELETE' | |||||
}); | |||||
}; | }; | ||||
return $http({ | |||||
url: '/v1/flow/delete.json', | |||||
params: param, | |||||
method: 'DELETE' | |||||
}); | |||||
}; | |||||
function notNumberAtLeastZero(num) { | function notNumberAtLeastZero(num) { | ||||
return num === undefined || num === '' || isNaN(num) || num < 0; | return num === undefined || num === '' || isNaN(num) || num < 0; | ||||
} | } | ||||
@@ -79,7 +79,7 @@ app.service('FlowServiceV1', ['$http', function ($http) { | |||||
return num === undefined || num === '' || isNaN(num) || num <= 0; | return num === undefined || num === '' || isNaN(num) || num <= 0; | ||||
} | } | ||||
this.checkRuleValid = function (rule) { | |||||
this.checkRuleValid = function (rule) { | |||||
if (rule.resource === undefined || rule.resource === '') { | if (rule.resource === undefined || rule.resource === '') { | ||||
alert('资源名称不能为空'); | alert('资源名称不能为空'); | ||||
return false; | return false; | ||||
@@ -110,6 +110,10 @@ app.service('FlowServiceV1', ['$http', function ($http) { | |||||
alert('排队超时时间必须大于 0'); | alert('排队超时时间必须大于 0'); | ||||
return false; | return false; | ||||
} | } | ||||
if (rule.clusterMode && (rule.clusterConfig === undefined || rule.clusterConfig.thresholdType === undefined)) { | |||||
alert('集群限流配置不正确'); | |||||
return false; | |||||
} | |||||
return true; | return true; | ||||
}; | }; | ||||
}]); | }]); |
@@ -1,41 +1,41 @@ | |||||
var app = angular.module('sentinelDashboardApp'); | var app = angular.module('sentinelDashboardApp'); | ||||
app.service('FlowServiceV2', ['$http', function ($http) { | app.service('FlowServiceV2', ['$http', function ($http) { | ||||
this.queryMachineRules = function (app, ip, port) { | |||||
var param = { | |||||
app: app, | |||||
ip: ip, | |||||
port: port | |||||
this.queryMachineRules = function (app, ip, port) { | |||||
var param = { | |||||
app: app, | |||||
ip: ip, | |||||
port: port | |||||
}; | |||||
return $http({ | |||||
url: '/v2/flow/rules', | |||||
params: param, | |||||
method: 'GET' | |||||
}); | |||||
}; | }; | ||||
return $http({ | |||||
url: '/v2/flow/rules', | |||||
params: param, | |||||
method: 'GET' | |||||
}); | |||||
}; | |||||
this.newRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule', | |||||
data: rule, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
this.newRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule', | |||||
data: rule, | |||||
method: 'POST' | |||||
}); | |||||
}; | |||||
this.saveRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule/' + rule.id, | |||||
data: rule, | |||||
method: 'PUT' | |||||
}); | |||||
}; | |||||
this.saveRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule/' + rule.id, | |||||
data: rule, | |||||
method: 'PUT' | |||||
}); | |||||
}; | |||||
this.deleteRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule/' + rule.id, | |||||
method: 'DELETE' | |||||
}); | |||||
}; | |||||
this.deleteRule = function (rule) { | |||||
return $http({ | |||||
url: '/v2/flow/rule/' + rule.id, | |||||
method: 'DELETE' | |||||
}); | |||||
}; | |||||
function notNumberAtLeastZero(num) { | function notNumberAtLeastZero(num) { | ||||
return num === undefined || num === '' || isNaN(num) || num < 0; | return num === undefined || num === '' || isNaN(num) || num < 0; | ||||
@@ -45,7 +45,7 @@ app.service('FlowServiceV2', ['$http', function ($http) { | |||||
return num === undefined || num === '' || isNaN(num) || num <= 0; | return num === undefined || num === '' || isNaN(num) || num <= 0; | ||||
} | } | ||||
this.checkRuleValid = function (rule) { | |||||
this.checkRuleValid = function (rule) { | |||||
if (rule.resource === undefined || rule.resource === '') { | if (rule.resource === undefined || rule.resource === '') { | ||||
alert('资源名称不能为空'); | alert('资源名称不能为空'); | ||||
return false; | return false; | ||||
@@ -76,10 +76,10 @@ app.service('FlowServiceV2', ['$http', function ($http) { | |||||
alert('排队超时时间必须大于 0'); | alert('排队超时时间必须大于 0'); | ||||
return false; | return false; | ||||
} | } | ||||
if (rule.clusterMode && (rule.clusterConfig === undefined || rule.clusterConfig.thresholdType === undefined)) { | |||||
alert('集群限流配置不正确'); | |||||
return false; | |||||
} | |||||
if (rule.clusterMode && (rule.clusterConfig === undefined || rule.clusterConfig.thresholdType === undefined)) { | |||||
alert('集群限流配置不正确'); | |||||
return false; | |||||
} | |||||
return true; | return true; | ||||
}; | }; | ||||
}]); | }]); |
@@ -525,6 +525,10 @@ body { | |||||
max-width: 200px; | max-width: 200px; | ||||
} | } | ||||
.width-200 { | |||||
max-width: 200px; | |||||
} | |||||
.witdh-300 { | .witdh-300 { | ||||
max-width: 300px; | max-width: 300px; | ||||
} | } | ||||
@@ -1,5 +1,13 @@ | |||||
<div class="row clearfix"> | <div class="row clearfix"> | ||||
<form role="form" class="form-horizontal"> | <form role="form" class="form-horizontal"> | ||||
<div class="form-group" ng-if="stateVO.currentMode == 0"> | |||||
<label class="col-sm-2 control-label">连接状态</label> | |||||
<div class="col-sm-4"> | |||||
<p class="form-control-static text-danger" ng-if="stateVO.client.clientConfig.clientState === 0">未连接</p> | |||||
<p class="form-control-static" ng-if="stateVO.client.clientConfig.clientState === 1">连接中</p> | |||||
<p class="form-control-static text-success" ng-if="stateVO.client.clientConfig.clientState === 2">已连接</p> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | <div class="form-group"> | ||||
<label class="col-sm-2 control-label">Token Server IP</label> | <label class="col-sm-2 control-label">Token Server IP</label> | ||||
<div class="col-sm-4"> | <div class="col-sm-4"> | ||||
@@ -1,9 +1,16 @@ | |||||
<div class="row clearfix"> | <div class="row clearfix"> | ||||
<form role="form" class="form-horizontal"> | <form role="form" class="form-horizontal"> | ||||
<div class="form-group" ng-if="stateVO.currentMode == 1"> | |||||
<label class="col-sm-2 control-label">Token Server 模式</label> | |||||
<div class="col-sm-4"> | |||||
<p class="form-control-static" ng-if="!stateVO.server.embedded">独立模式 (Alone)</p> | |||||
<p class="form-control-static" ng-if="stateVO.server.embedded">嵌入模式 (Embedded)</p> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | <div class="form-group"> | ||||
<label class="col-sm-2 control-label">Token Server 端口</label> | <label class="col-sm-2 control-label">Token Server 端口</label> | ||||
<div class="col-sm-4"> | <div class="col-sm-4"> | ||||
<input type="number" min="0" max="65535" required class="form-control highlight-border" ng-model='stateVO.server.transport.port' placeholder='请指定 Token Server 端口' /> | |||||
<input type="number" min="1" max="65535" required class="form-control highlight-border" ng-model='stateVO.server.transport.port' placeholder='请指定 Token Server 端口' /> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
@@ -12,5 +19,11 @@ | |||||
<input type="text" required class="form-control highlight-border" ng-model='stateVO.server.namespaceSetStr' placeholder='请指定服务端服务的命名空间集合(以,分隔)' /> | <input type="text" required class="form-control highlight-border" ng-model='stateVO.server.namespaceSetStr' placeholder='请指定服务端服务的命名空间集合(以,分隔)' /> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">最大全局 QPS</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" min="0" max="100000" required class="form-control highlight-border" ng-model='stateVO.server.flow.maxAllowedQps' placeholder='请指定服务端最大全局 QPS' /> | |||||
</div> | |||||
</div> | |||||
</form> | </form> | ||||
</div> | </div> |
@@ -0,0 +1,118 @@ | |||||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;"> | |||||
<div class="col-md-6" style="margin-bottom: 10px;"> | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | |||||
</div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div class="container-fluid"> | |||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;"> | |||||
<div class="col-md-12"> | |||||
<div class="card"> | |||||
<div class="inputs-header"> | |||||
<span class="brand" style="font-size: 13px;">集群限流 - 机器分配/管控</span> | |||||
</div> | |||||
<!-- error panel --> | |||||
<div class="row clearfix" ng-if="loadError"> | |||||
<div class="col-md-6 col-md-offset-3"> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-body"> | |||||
<center> | |||||
<p>{{loadError.message}}</p> | |||||
</center> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!--.tools-header --> | |||||
<div class="card-body" style="padding: 0px 0px;" ng-if="!loadError"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Server 列表</label> | |||||
<div class="col-sm-4"> | |||||
<select ng-model="tmp.curChosenServer" ng-change="onCurrentServerChange()" size="8" | |||||
ng-options="serverGroup.machineId for serverGroup in clusterMap" | |||||
class="form-control"></select> | |||||
</div> | |||||
<button type="button" class="btn btn-outline-warning" ng-click="removeFromServerList()">移除 | |||||
</button> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Token Server 端口</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" class="form-control highlight-border" | |||||
ng-disabled="!tmp.curChosenServer.belongToApp" | |||||
ng-model='tmp.curChosenServer.port' placeholder='port' min="1" max="65535"/> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">命名空间集合</label> | |||||
<div class="col-sm-4"> | |||||
<input type="text" required class="form-control highlight-border" | |||||
ng-disabled="!tmp.curChosenServer.belongToApp" | |||||
ng-model='tmp.curChosenServer.namespaceSetStr' | |||||
placeholder='请指定服务端服务的命名空间集合(以,分隔)'/> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
<form role="form" class="form-inline" style="margin-top: 30px; margin-left: 20px;"> | |||||
<div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-12"> | |||||
<label class="control-label" style="width: 200px; text-align: center;">当前对应客户端列表</label> | |||||
<select size="8" multiple="multiple" ng-model="tmp.curClientChosen" | |||||
ng-options="ip for ip in tmp.curChosenServer.clientSet" | |||||
class="form-control" style="width: 100%;"></select> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-12"> | |||||
<button type="button" class="btn btn-outline-primary" | |||||
ng-disabled="!tmp.curChosenServer || !tmp.curChosenServer.machineId" | |||||
ng-click="moveToServerGroup()">← | |||||
</button> | |||||
<button type="button" class="btn btn-outline-primary" | |||||
ng-click="moveToRemainingSharePool()">→ | |||||
</button> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-12"> | |||||
<label class="control-label" style="width: 220px; text-align: center;">未分配机器列表</label> | |||||
<div> | |||||
<select size="8" multiple="multiple" ng-model="tmp.curRemainingClientChosen" | |||||
ng-options="ip for ip in remainingClientAddressList" | |||||
class="form-control" style="width: 100%;"> | |||||
</select> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-6"> | |||||
<button type="button" class="btn btn-outline-primary" | |||||
ng-click="addToServerList()">添加为 server | |||||
</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
<div class="separator"></div> | |||||
<div style="margin-top: 20px;"> | |||||
<button type="button" style="margin: 0 10px 10px 10px;" class="btn btn-outline-success" | |||||
ng-click="saveAndApplyAssign()">保存并执行分配 | |||||
</button> | |||||
</div> | |||||
</div> | |||||
<!-- .card-body --> | |||||
</div> | |||||
<!-- .card --> | |||||
</div> | |||||
<!-- .col-md-12 --> | |||||
</div> | |||||
<!-- --> | |||||
</div> | |||||
<!-- .container-fluid --> |
@@ -0,0 +1,73 @@ | |||||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;"> | |||||
<div class="col-md-6" style="margin-bottom: 10px;"> | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | |||||
</div> | |||||
<div class="col-md-6"> | |||||
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.clusterAppServerList({app: app})"> | |||||
Token Server 列表 | |||||
</a> | |||||
</div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div class="container-fluid"> | |||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;"> | |||||
<div class="col-md-12"> | |||||
<div class="card"> | |||||
<div class="inputs-header"> | |||||
<span class="brand" style="font-size: 13px;">集群限流 - Token Client 列表</span> | |||||
</div> | |||||
<!-- error panel --> | |||||
<div class="row clearfix" ng-if="loadError"> | |||||
<div class="col-md-6 col-md-offset-3"> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-body"> | |||||
<center> | |||||
<p>{{loadError.message}}</p> | |||||
</center> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!--.tools-header --> | |||||
<div class="card-body" style="padding: 0px 0px;" ng-if="!loadError"> | |||||
<!-- table start --> | |||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;"> | |||||
<thead> | |||||
<tr style="background: #F3F5F7;"> | |||||
<td style="min-width: 12%;">Client ID</td> | |||||
<td>Server IP</td> | |||||
<td>Server 端口</td> | |||||
<td>连接状态</td> | |||||
<td style="min-width: 15%;">操作</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr ng-repeat="clientVO in clientVOList"> | |||||
<td style="word-wrap:break-word;word-break:break-all;">{{clientVO.id}}</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;">{{clientVO.state.clientConfig.serverHost}}</td> | |||||
<td>{{clientVO.state.clientConfig.serverPort}}</td> | |||||
<td> | |||||
<span class="form-control-static text-danger" ng-if="clientVO.state.clientConfig.clientState === 0">未连接</span> | |||||
<span class="form-control-static" ng-if="clientVO.state.clientConfig.clientState === 1">连接中</span> | |||||
<span class="form-control-static text-success" ng-if="clientVO.state.clientConfig.clientState === 2">已连接</span> | |||||
</td> | |||||
<td> | |||||
<button class="btn btn-xs btn-outline-primary" type="button" | |||||
ng-click="modifyClientConfigDialog(clientVO)" style="font-size: 12px; height:25px;">编辑配置</button> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<!-- .card-body --> | |||||
</div> | |||||
<!-- .card --> | |||||
</div> | |||||
<!-- .col-md-12 --> | |||||
</div> | |||||
<!-- --> | |||||
</div> | |||||
<!-- .container-fluid --> |
@@ -0,0 +1,87 @@ | |||||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;"> | |||||
<div class="col-md-6" style="margin-bottom: 10px;"> | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | |||||
</div> | |||||
<div class="col-md-6"> | |||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-if="!loadError" ng-click="newServerDialog()"> | |||||
<i class="fa fa-plus"></i> 新增 Token Server</button> | |||||
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.clusterAppClientList({app: app})"> | |||||
Token Client 列表 | |||||
</a> | |||||
</div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div class="container-fluid"> | |||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;"> | |||||
<div class="col-md-12"> | |||||
<div class="card"> | |||||
<div class="inputs-header"> | |||||
<span class="brand" style="font-size: 13px;">集群限流 - Token Server 列表</span> | |||||
<input class="form-control width-200" placeholder="搜索 server..." ng-model="searchKey"> | |||||
</div> | |||||
<!-- error panel --> | |||||
<div class="row clearfix" ng-if="loadError"> | |||||
<div class="col-md-6 col-md-offset-3"> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-body"> | |||||
<center> | |||||
<p>{{loadError.message}}</p> | |||||
</center> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!--.tools-header --> | |||||
<div class="card-body" style="padding: 0px 0px;" ng-if="!loadError"> | |||||
<!-- table start --> | |||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;"> | |||||
<thead> | |||||
<tr style="background: #F3F5F7;"> | |||||
<td style="width: 15%;">Server ID</td> | |||||
<td style="width: 10%;">Port</td> | |||||
<td style="width: 15%;">命名空间集合</td> | |||||
<td>总连接数</td> | |||||
<td>QPS 总览</td> | |||||
<td style="width: 20%;">操作</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr ng-repeat="serverVO in serverVOList | filter: {id: searchKey}"> | |||||
<td style="word-wrap:break-word;word-break:break-all;">{{serverVO.id}}</td> | |||||
<td>{{serverVO.port}}</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | |||||
{{serverVO.state.namespaceSetStr}} | |||||
</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | |||||
{{serverVO.connectedCount}} | |||||
</td> | |||||
<td> | |||||
{{serverVO.state.requestLimitDataStr}} | |||||
<!--<p ng-repeat="crl in serverVO.state.requestLimitData">--> | |||||
<!--<span ng-if="crl.namespace === app">{{crl.namespace}}:{{crl.currentQps}} / {{crl.maxAllowedQps}}</span>--> | |||||
<!--</p>--> | |||||
</td> | |||||
<td> | |||||
<button class="btn btn-xs btn-outline-primary" type="button" | |||||
ng-click="viewConnectionDetail(serverVO)" style="font-size: 12px; height:25px;">连接详情</button> | |||||
<button class="btn btn-xs btn-outline-primary" type="button" | |||||
ng-click="modifyServerAssignConfig(serverVO.id)" style="font-size: 12px; height:25px;">管理</button> | |||||
<button class="btn btn-xs btn-outline-danger" type="button" | |||||
ng-click="unbindServer(serverVO.id)" style="font-size: 12px; height:25px;">移除</button> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<!-- .card-body --> | |||||
</div> | |||||
<!-- .card --> | |||||
</div> | |||||
<!-- .col-md-12 --> | |||||
</div> | |||||
<!-- --> | |||||
</div> | |||||
<!-- .container-fluid --> |
@@ -0,0 +1,88 @@ | |||||
<div class="row" style="margin-left: 1px; margin-top:10px; height: 50px;"> | |||||
<div class="col-md-6" style="margin-bottom: 10px;"> | |||||
<span style="font-size: 30px;font-weight: bold;">{{app}}</span> | |||||
</div> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div class="container-fluid"> | |||||
<div class="row" style="margin-top: 20px; margin-bottom: 20px;"> | |||||
<div class="col-md-12"> | |||||
<div class="card"> | |||||
<div class="inputs-header"> | |||||
<span class="brand" style="font-size: 13px;">集群限流 - Token Server 总览</span> | |||||
</div> | |||||
<!-- error panel --> | |||||
<div class="row clearfix" ng-if="loadError"> | |||||
<div class="col-md-6 col-md-offset-3"> | |||||
<div class="panel panel-default"> | |||||
<div class="panel-body"> | |||||
<center> | |||||
<p>{{loadError.message}}</p> | |||||
</center> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!--.tools-header --> | |||||
<div class="card-body" style="padding: 0px 0px;" ng-if="!loadError"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group" hidden> | |||||
<label class="col-sm-2 control-label">Token Server 列表</label> | |||||
<div class="col-sm-4"> | |||||
<select ng-model="tmp.curChosenServer" ng-change="onChosenServerChange()" | |||||
ng-options="serverEntity.id for serverEntity in serverVOList" | |||||
class="form-control"></select> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
<!-- table start --> | |||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;"> | |||||
<thead> | |||||
<tr style="background: #F3F5F7;"> | |||||
<td style="width: 12%;">Server ID</td> | |||||
<td style="width: 5%;">Port</td> | |||||
<td style="width: 10%;">命名空间集合</td> | |||||
<td>总连接数</td> | |||||
<td>连接情况</td> | |||||
<td>QPS 总览</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr ng-repeat="serverVO in clientVOList"> | |||||
<td style="word-wrap:break-word;word-break:break-all;">{{serverVO.id}}</td> | |||||
<td>{{serverVO.port}}</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | |||||
{{serverVO.state.namespaceSetStr}} | |||||
</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | |||||
{{serverVO.connectedCount}} | |||||
</td> | |||||
<td> | |||||
<p ng-repeat="cg in serverVO.state.connection"> | |||||
namespace: {{cg.namespace}}, 连接数: {{cg.connectedCount}}, clients: | |||||
{{generateConnectionSet(cg.connectionSet)}} | |||||
</p> | |||||
</td> | |||||
<td> | |||||
<p ng-repeat="crl in serverVO.state.requestLimitData"> | |||||
namespace: {{crl.namespace}}, 当前 QPS: {{crl.currentQps}}, 最大允许 QPS: | |||||
{{crl.maxAllowedQps}} | |||||
</p> | |||||
</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
<!-- .card-body --> | |||||
</div> | |||||
<!-- .card --> | |||||
</div> | |||||
<!-- .col-md-12 --> | |||||
</div> | |||||
<!-- --> | |||||
</div> | |||||
<!-- .container-fluid --> |
@@ -12,8 +12,7 @@ | |||||
<div class="card"> | <div class="card"> | ||||
<div class="inputs-header"> | <div class="inputs-header"> | ||||
<span class="brand" style="font-size: 13px;">集群限流</span> | <span class="brand" style="font-size: 13px;">集群限流</span> | ||||
<button class="btn btn-primary" style="float: right; margin-right: 10px; height: 30px;font-size: 12px;" ng-click="getMachineRules()">刷新</button> | |||||
<input class="form-control witdh-200" placeholder="关键字" ng-model="searchKey"> | |||||
<input class="form-control witdh-200" placeholder="机器搜索" ng-model="searchKey"> | |||||
<div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;"> | <div class="control-group" style="float:right;margin-right: 10px;margin-bottom: -10px;"> | ||||
<selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel" | <selectize id="gsInput" class="selectize-input-200" config="macsInputConfig" options="macsInputOptions" ng-model="macInputModel" | ||||
placeholder="机器"></selectize> | placeholder="机器"></selectize> | ||||
@@ -34,8 +33,7 @@ | |||||
</div> | </div> | ||||
<!--.tools-header --> | <!--.tools-header --> | ||||
<div class="card-body" style="padding: 0px 0px;"> | |||||
<!--<span class="brand" style="font-weight:bold;">集群限流状态</span>--> | |||||
<div class="card-body" style="padding: 0px 0px;" ng-if="!loadError"> | |||||
<form role="form" class="form-horizontal"> | <form role="form" class="form-horizontal"> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<label class="col-sm-2 control-label">当前模式</label> | <label class="col-sm-2 control-label">当前模式</label> | ||||
@@ -80,7 +78,8 @@ | |||||
<div class="separator"></div> | <div class="separator"></div> | ||||
<div clss="row" style="margin-top: 20px;"> | <div clss="row" style="margin-top: 20px;"> | ||||
<button style="margin: 0 10px 10px 10px;" class="btn btn-outline-success" ng-click="saveConfig()">保存配置</button> | |||||
<button style="margin: 0 10px 10px 10px;" class="btn btn-outline-success" | |||||
ng-click="saveConfig()">保存配置</button> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -0,0 +1,40 @@ | |||||
<div> | |||||
<span class="brand" style="font-weight:bold;">修改 Token Client 配置</span> | |||||
<div class="card" style="margin-top: 20px;margin-bottom: 10px;"> | |||||
<div class="panel-body"> | |||||
<div class="row"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-3 control-label">Client ID</label> | |||||
<div class="col-sm-4"> | |||||
<p class="form-control-static">{{ccDialogData.clientId}}</p> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-3 control-label">Token Server IP</label> | |||||
<div class="col-sm-4"> | |||||
<input type="text" class="form-control highlight-border" ng-model='ccDialogData.serverHost' placeholder='请指定 Token Server IP' /> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-3 control-label">Token Server 端口</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" min="0" max="65535" required class="form-control highlight-border" ng-model='ccDialogData.serverPort' placeholder='请指定 Token Server 端口' /> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-3 control-label">请求超时时间(ms)</label> | |||||
<div class="col-sm-4"> | |||||
<input type="number" min="0" required class="form-control highlight-border" ng-model='ccDialogData.requestTimeout' placeholder='请指定请求超时时间(ms)' /> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div clss="row" style="margin-top: 20px;"> | |||||
<button class="btn btn-outline-danger" style="float:right; height: 30px;font-size: 12px;margin-left: 10px;" ng-click="ccDialog.close()">取消</button> | |||||
<button class="btn btn-outline-success" style="float:right; height: 30px;font-size: 12px;margin-left: 10px;" ng-click="doModifyClientConfig()">保存</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
@@ -0,0 +1,139 @@ | |||||
<div> | |||||
<span class="brand" style="font-weight:bold;">{{serverAssignDialogData.title}}</span> | |||||
<div class="card" style="margin-top: 20px;margin-bottom: 10px;"> | |||||
<div class="panel-body"> | |||||
<div class="row"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div ng-if="serverAssignDialogData.type == 'edit'"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Token Server</label> | |||||
<div class="col-sm-4"> | |||||
<p class="form-control-static">{{serverAssignDialogData.serverData.currentServer}}</p> | |||||
</div> | |||||
<label class="col-sm-2 control-label">Server 端口</label> | |||||
<div class="col-sm-3"> | |||||
<input type="number" min="1" max="65535" class="form-control highlight-border" | |||||
ng-disabled="!serverAssignDialogData.serverData.belongToApp" | |||||
ng-model='serverAssignDialogData.serverData.serverPort' placeholder='请输入 Token Server 端口'/> | |||||
</div> | |||||
</div> | |||||
<div class="form-group" ng-if="serverAssignDialogData.serverData.belongToApp"> | |||||
<label class="col-sm-2 control-label" | |||||
title="server 最大允许的总 QPS,注意 embedded 模式下不要设的太大">最大允许 QPS</label> | |||||
<div class="col-sm-3"> | |||||
<input type="number" min="0" max="200000" class="form-control highlight-border" | |||||
ng-model='serverAssignDialogData.serverData.maxAllowedQps' placeholder='请输入 server 最大允许 QPS'/> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div ng-if="serverAssignDialogData.type == 'add'"> | |||||
<div class="form-group" > | |||||
<label class="col-sm-2 control-label">机器类型</label> | |||||
<div class="col-sm-4"> | |||||
<div class="form-control highlight-border" align="center"> | |||||
<input type="radio" name="strategy" value="0" checked ng-model='serverAssignDialogData.serverData.serverType' /> 应用内机器 | |||||
<input type="radio" name="strategy" value="1" ng-model='serverAssignDialogData.serverData.serverType' /> 外部指定机器 | |||||
</div> | |||||
</div> | |||||
<div ng-if="serverAssignDialogData.serverData.serverType == 1"> | |||||
<div class="col-sm-6"> | |||||
<p class="form-control-static text-primary" style="font-size: x-small;">若指定外部 server,请先在相应页面对外部 server 进行配置,然后在此页面指定。</p> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div ng-if="serverAssignDialogData.serverData.serverType == 0"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">选择机器</label> | |||||
<div class="col-sm-4"> | |||||
<select ng-model="serverAssignDialogData.serverData.currentServer" ng-change="onCurrentServerChange()" | |||||
ng-options="machineId for machineId in remainingMachineList" | |||||
class="form-control"></select> | |||||
</div> | |||||
<label class="col-sm-2 control-label">Server 端口</label> | |||||
<div class="col-sm-3"> | |||||
<input type="number" min="1" max="65535" class="form-control highlight-border" | |||||
ng-model='serverAssignDialogData.serverData.serverPort' placeholder='请输入 Token Server 端口号'/> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label" | |||||
title="server 最大允许的总 QPS,注意 embedded 模式下不要设的太大">最大允许 QPS</label> | |||||
<div class="col-sm-3"> | |||||
<input type="number" min="0" max="200000" class="form-control highlight-border" | |||||
ng-model='serverAssignDialogData.serverData.maxAllowedQps' placeholder='请输入 server 最大允许 QPS'/> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div ng-if="serverAssignDialogData.serverData.serverType == 1"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">Server IP</label> | |||||
<div class="col-sm-4"> | |||||
<input type="text" class="form-control highlight-border" | |||||
ng-model='serverAssignDialogData.serverData.currentServer' placeholder='请输入独立的 Token Server IP'/> | |||||
</div> | |||||
<label class="col-sm-2 control-label">Server 端口</label> | |||||
<div class="col-sm-3"> | |||||
<input type="number" min="1" max="65535" class="form-control highlight-border" | |||||
ng-model='serverAssignDialogData.serverData.serverPort' placeholder='请输入 Token Server 端口号'/> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
<!-- assign form start --> | |||||
<form role="form" class="form-inline" ng-if="serverAssignDialogData.serverData.currentServer" | |||||
style="margin-top: 30px; margin-left: 20px; text-align: center;"> | |||||
<div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-12"> | |||||
<label class="control-label" style="width: 220px; text-align: center;">请从中选取 client:</label> | |||||
<div> | |||||
<select size="8" multiple="multiple" ng-model="tmp.curRemainingClientChosen" | |||||
ng-options="ip for ip in remainingMachineList | filter: notChosenServer" | |||||
class="form-control" style="width: 100%;"> | |||||
</select> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-12"> | |||||
<button type="button" class="btn btn-outline-primary" | |||||
ng-click="moveToRemainingSharePool()">← | |||||
</button> | |||||
<button type="button" class="btn btn-outline-primary" | |||||
ng-click="moveToServerGroup()">→ | |||||
</button> | |||||
</div> | |||||
</div> | |||||
<div class="form-group"> | |||||
<div class="col-sm-12"> | |||||
<label class="control-label" style="width: 200px; text-align: center;">已选取的 client 列表</label> | |||||
<div> | |||||
<select size="8" multiple="multiple" ng-model="tmp.curClientChosen" | |||||
ng-options="ip for ip in serverAssignDialogData.serverData.clientSet" | |||||
class="form-control" style="width: 100%;"></select> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
</div> | |||||
<div class="separator"></div> | |||||
<div clss="row" style="margin-top: 20px;"> | |||||
<button class="btn btn-outline-danger" style="float:right; height: 30px;font-size: 12px;margin-left: 10px;" ng-click="serverAssignDialog.close()">取消</button> | |||||
<button class="btn btn-outline-success" style="float:right; height: 30px;font-size: 12px;margin-left: 10px;" ng-click="saveAssignForDialog()">{{serverAssignDialogData.confirmBtnText}}</button> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
@@ -0,0 +1,37 @@ | |||||
<div> | |||||
<span class="brand" style="font-weight:bold;">连接详情</span> | |||||
<div class="card" style="margin-top: 20px;margin-bottom: 10px;"> | |||||
<div class="panel-body"> | |||||
<div class="row"> | |||||
<form role="form" class="form-horizontal"> | |||||
<div class="form-group"> | |||||
<label class="col-sm-3 control-label">Token Server</label> | |||||
<div class="col-sm-4"> | |||||
<p class="form-control-static">{{connectionDetailDialogData.serverData.id}}</p> | |||||
</div> | |||||
</div> | |||||
</form> | |||||
<div class="col-md-12"> | |||||
<!-- table start --> | |||||
<table class="table" style="border-left: none; border-right:none;margin-top: 10px;"> | |||||
<thead> | |||||
<tr style="background: #F3F5F7;"> | |||||
<td style="min-width: 15%;" class="text-center">命名空间</td> | |||||
<td class="text-center">连接数</td> | |||||
<td class="text-center">连接详情</td> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<tr ng-repeat="cg in connectionDetailDialogData.serverData.state.connection"> | |||||
<td style="word-wrap:break-word;word-break:break-all;" class="text-center">{{cg.namespace}}</td> | |||||
<td style="word-wrap:break-word;word-break:break-all;" class="text-center">{{cg.connectedCount}}</td> | |||||
<td class="text-center">{{generateConnectionSet(cg.connectionSet)}}</td> | |||||
</tr> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> |
@@ -15,7 +15,7 @@ | |||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<label class="col-sm-2 control-label" title="流控针对应用,即流量入口的调用来源(origin)">流控应用</label> | |||||
<label class="col-sm-2 control-label" data-toggle="tooltip" title="流控针对应用,即流量入口的调用来源(origin)">来源应用</label> | |||||
<div class="col-sm-9"> | <div class="col-sm-9"> | ||||
<input type="text" class="form-control highlight-border" ng-model='currentRule.limitApp' placeholder='指调用方,"default"表示所有应用。' | <input type="text" class="form-control highlight-border" ng-model='currentRule.limitApp' placeholder='指调用方,"default"表示所有应用。' | ||||
/> | /> | ||||
@@ -60,7 +60,7 @@ | |||||
<div class="col-sm-4"> | <div class="col-sm-4"> | ||||
<div class="form-control highlight-border" align="center"> | <div class="form-control highlight-border" align="center"> | ||||
<input type="radio" name="clusterThresholdType" value="0" ng-model='currentRule.clusterConfig.thresholdType' /> 单机均摊 | <input type="radio" name="clusterThresholdType" value="0" ng-model='currentRule.clusterConfig.thresholdType' /> 单机均摊 | ||||
<input type="radio" name="clusterThresholdType" value="1" ng-model='currentRule.clusterConfig.thresholdType' /> Global | |||||
<input type="radio" name="clusterThresholdType" value="1" ng-model='currentRule.clusterConfig.thresholdType' /> 总体阈值 | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -25,12 +25,42 @@ | |||||
</div> | </div> | ||||
<div class="form-group"> | <div class="form-group"> | ||||
<label class="col-sm-2 control-label">限流阈值</label> | |||||
<div class="col-sm-9"> | |||||
<input type="number" class="form-control highlight-border" ng-model='currentRule.rule.count' placeholder='请填入限流阈值' /> | |||||
<div ng-if="!currentRule.rule.clusterMode"> | |||||
<label class="col-sm-2 control-label">单机阈值</label> | |||||
<div class="col-sm-9"> | |||||
<input type="number" class="form-control highlight-border" ng-model='currentRule.rule.count' placeholder='单机阈值' /> | |||||
</div> | |||||
</div> | |||||
<div ng-if="currentRule.rule.clusterMode && currentRule.rule.clusterConfig.thresholdType == 0"> | |||||
<label class="col-sm-2 control-label">均摊阈值</label> | |||||
<div class="col-sm-9"> | |||||
<input type="number" class="form-control highlight-border" ng-model='currentRule.rule.count' placeholder='集群均摊阈值' /> | |||||
</div> | |||||
</div> | |||||
<div ng-if="currentRule.rule.clusterMode && currentRule.rule.clusterConfig.thresholdType == 1"> | |||||
<label class="col-sm-2 control-label">集群阈值</label> | |||||
<div class="col-sm-9"> | |||||
<input type="number" class="form-control highlight-border" ng-model='currentRule.rule.count' placeholder='集群总体阈值' /> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
<div class="form-group"> | |||||
<label class="col-sm-2 control-label">是否集群</label> | |||||
<div class="col-sm-2"> | |||||
<input type="checkbox" name="clusterMode" ng-model="currentRule.rule.clusterMode"> | |||||
</div> | |||||
<div ng-if="currentRule.rule.clusterMode"> | |||||
<label class="col-sm-3 control-label">集群阈值模式</label> | |||||
<div class="col-sm-4"> | |||||
<div class="form-control highlight-border" align="center"> | |||||
<input type="radio" name="clusterThresholdType" value="0" ng-model='currentRule.rule.clusterConfig.thresholdType' /> 单机均摊 | |||||
<input type="radio" name="clusterThresholdType" value="1" ng-model='currentRule.rule.clusterConfig.thresholdType' /> 总体阈值 | |||||
</div> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
<!-- exclusion item part start --> | <!-- exclusion item part start --> | ||||
<div ng-if="!paramFlowRuleDialog.showAdvanceButton"> | <div ng-if="!paramFlowRuleDialog.showAdvanceButton"> | ||||
@@ -17,7 +17,7 @@ | |||||
<input type="radio" name="grade" value="2" ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" /> 线程数 | <input type="radio" name="grade" value="2" ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" /> 线程数 | ||||
<!--qps --> | <!--qps --> | ||||
<input type="radio" name="grade" value="3" checked ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" | <input type="radio" name="grade" value="3" checked ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" | ||||
/> QPS | |||||
/> 入口 QPS | |||||
</div> | </div> | ||||
<div class="form-control highlight-border" ng-if="systemRuleDialog.type == 'add'" align="center"> | <div class="form-control highlight-border" ng-if="systemRuleDialog.type == 'add'" align="center"> | ||||
<!--avgLoad --> | <!--avgLoad --> | ||||
@@ -28,7 +28,7 @@ | |||||
<input type="radio" name="grade" value="2" ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" /> 线程数 | <input type="radio" name="grade" value="2" ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" /> 线程数 | ||||
<!--qps --> | <!--qps --> | ||||
<input type="radio" name="grade" value="3" checked ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" | <input type="radio" name="grade" value="3" checked ng-model='currentRule.grade' ng-disabled="systemRuleDialog.type == 'edit'" | ||||
/> QPS | |||||
/> 入口 QPS | |||||
</div> | </div> | ||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -5,8 +5,8 @@ | |||||
<div class="col-md-6"> | <div class="col-md-6"> | ||||
<button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()"> | <button class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ng-disabled="!macInputModel" ng-click="addNewRule()"> | ||||
<i class="fa fa-plus"></i> 新增流控规则</button> | <i class="fa fa-plus"></i> 新增流控规则</button> | ||||
<a class="btn btn-outline-success" style="float: right; margin-right: 10px;" ui-sref="dashboard.flow({app: app})"> | |||||
回到新版</a> | |||||
<!--<a class="btn btn-outline-success" style="float: right; margin-right: 10px;" ui-sref="dashboard.flow({app: app})">--> | |||||
<!--回到集群页面</a>--> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -35,24 +35,24 @@ | |||||
<td style="width: 40%"> | <td style="width: 40%"> | ||||
资源名 | 资源名 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
流控应用 | |||||
<td style="width: 8%;"> | |||||
来源应用 | |||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
<td style="width: 8%;"> | |||||
流控模式 | 流控模式 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
<td style="width: 8%;"> | |||||
阈值类型 | 阈值类型 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | |||||
单机阈值 | |||||
<td style="width: 6%;"> | |||||
阈值 | |||||
</td> | |||||
<td style="width: 8%;"> | |||||
阈值模式 | |||||
</td> | </td> | ||||
<td style="width: 10%;"> | <td style="width: 10%;"> | ||||
流控效果 | 流控效果 | ||||
</td> | </td> | ||||
<!--<td style="width: 8%;">--> | |||||
<!--状态--> | |||||
<!--</td>--> | |||||
<td style="width: 12%;"> | <td style="width: 12%;"> | ||||
操作 | 操作 | ||||
</td> | </td> | ||||
@@ -74,10 +74,14 @@ | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | <td style="word-wrap:break-word;word-break:break-all;"> | ||||
{{rule.count}} | {{rule.count}} | ||||
</td> | </td> | ||||
<td> | |||||
<span>{{generateThresholdTypeShow(rule)}}</span> | |||||
</td> | |||||
<td> | <td> | ||||
<span ng-if="rule.controlBehavior == 0">快速失败</span> | <span ng-if="rule.controlBehavior == 0">快速失败</span> | ||||
<span ng-if="rule.controlBehavior == 1">Warm Up</span> | <span ng-if="rule.controlBehavior == 1">Warm Up</span> | ||||
<span ng-if="rule.controlBehavior == 2">排队等待</span> | <span ng-if="rule.controlBehavior == 2">排队等待</span> | ||||
<span ng-if="rule.controlBehavior == 3">预热排队</span> | |||||
</td> | </td> | ||||
<td> | <td> | ||||
<button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button> | <button class="btn btn-xs btn-default" type="button" ng-click="editRule(rule)" style="font-size: 12px; height:25px;">编辑</button> |
@@ -7,7 +7,8 @@ | |||||
<i class="fa fa-plus"></i> 新增流控规则 | <i class="fa fa-plus"></i> 新增流控规则 | ||||
</button> | </button> | ||||
<a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})"> | <a class="btn btn-default-inverse" style="float: right; margin-right: 10px;" ui-sref="dashboard.flowV1({app: app})"> | ||||
回到旧版(单机)</a> | |||||
回到单机页面 | |||||
</a> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
@@ -31,7 +32,7 @@ | |||||
资源名 | 资源名 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | <td style="width: 10%;"> | ||||
流控应用 | |||||
来源应用 | |||||
</td> | </td> | ||||
<td style="width: 8%;"> | <td style="width: 8%;"> | ||||
流控模式 | 流控模式 | ||||
@@ -40,10 +41,10 @@ | |||||
阈值类型 | 阈值类型 | ||||
</td> | </td> | ||||
<td style="width: 8%;"> | <td style="width: 8%;"> | ||||
单机阈值 | |||||
阈值 | |||||
</td> | </td> | ||||
<td style="width: 8%;"> | <td style="width: 8%;"> | ||||
是否集群 | |||||
阈值模式 | |||||
</td> | </td> | ||||
<td style="width: 8%;"> | <td style="width: 8%;"> | ||||
流控效果 | 流控效果 | ||||
@@ -70,8 +71,7 @@ | |||||
{{rule.count}} | {{rule.count}} | ||||
</td> | </td> | ||||
<td> | <td> | ||||
<span ng-if="rule.clusterMode">是</span> | |||||
<span ng-if="!rule.clusterMode">否</span> | |||||
<span>{{generateThresholdTypeShow(rule)}}</span> | |||||
</td> | </td> | ||||
<td> | <td> | ||||
<span ng-if="rule.controlBehavior == 0">快速失败</span> | <span ng-if="rule.controlBehavior == 0">快速失败</span> |
@@ -53,7 +53,10 @@ | |||||
流控模式 | 流控模式 | ||||
</td> | </td> | ||||
<td style="width: 10%;"> | <td style="width: 10%;"> | ||||
单机阈值 | |||||
阈值 | |||||
</td> | |||||
<td style="width: 8%;"> | |||||
是否集群 | |||||
</td> | </td> | ||||
<td style="width: 10%;"> | <td style="width: 10%;"> | ||||
例外项数目 | 例外项数目 | ||||
@@ -74,6 +77,10 @@ | |||||
<td style="word-wrap:break-word;word-break:break-all;"> | <td style="word-wrap:break-word;word-break:break-all;"> | ||||
{{ruleEntity.rule.count}} | {{ruleEntity.rule.count}} | ||||
</td> | </td> | ||||
<td> | |||||
<span ng-if="ruleEntity.rule.clusterMode">是</span> | |||||
<span ng-if="!ruleEntity.rule.clusterMode">否</span> | |||||
</td> | |||||
<td> | <td> | ||||
{{ruleEntity.rule.paramFlowItemList == undefined ? 0 : ruleEntity.rule.paramFlowItemList.length}} | {{ruleEntity.rule.paramFlowItemList == undefined ? 0 : ruleEntity.rule.paramFlowItemList.length}} | ||||
</td> | </td> | ||||