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();
|
let serverCommandPortMap = 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(machineId)) {
|
tmpMap.set(machineId, group);
|
}
|
serverCommandPortMap.set(ip + ':' + e.state.server.port, e.commandPort);
|
});
|
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;
|
}
|
|
let serverHostPort = targetServer + ':' + targetPort;
|
|
if (serverCommandPortMap.has(serverHostPort)) {
|
let serverCommandPort = serverCommandPortMap.get(serverHostPort);
|
let g;
|
if (serverCommandPort < 0) {
|
// Not belong to this app.
|
g = tmpMap.get(serverHostPort);
|
} else {
|
// Belong to this app.
|
g = tmpMap.get(targetServer + '@' + serverCommandPort);
|
}
|
g.clientSet.push(machineId);
|
} else {
|
let group = {
|
ip: targetServer,
|
machineId: serverHostPort,
|
port: targetPort,
|
clientSet: [machineId],
|
belongToApp: false,
|
};
|
tmpMap.set(serverHostPort, group);
|
// Indicates that it's not belonging to current app.
|
serverCommandPortMap.set(serverHostPort, -1);
|
}
|
|
// if (!tmpMap.has(serverHostPort)) {
|
// 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.split(':')[0];
|
}
|
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 = (serverVO) => {
|
let id = serverVO.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: serverVO.belongToApp,
|
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);
|
} 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');
|
}
|
};
|
}]);
|