Authored by qinchao

伸缩组扩容

... ... @@ -97,183 +97,93 @@
</div>
</div>
</div>
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" style="margin:0 auto;margin-top:20px;width: 600px" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" style="width: 100%">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal"
aria-hidden="true">&times;</button>
<h4 class="modal-title" id="myModalLabel"></h4>
</div>
<div class="modal-body">
<form id="hostGroupForm" class="form-horizontal">
<div class="form-group">
<label style="vertical-align: middle" class="col-sm-2 control-label">免于缩减的实例数:</label>
<div class="col-sm-8">
<input type="text" class="form-control" readonly="readonly" id="protectedFromCount" name="protectedFromCount" size="40" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">最少实例数:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="minSize" name="minSize" size="40"
onkeyup="this.value=this.value.replace(/\D/g,'')" onafterpaste="this.value=this.value.replace(/\D/g,'')" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">最多实例数:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="maxSize" name="maxSize" size="40"
onkeyup="this.value=this.value.replace(/\D/g,'')" onafterpaste="this.value=this.value.replace(/\D/g,'')" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">期望容量:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="desiredCapacity" name="desiredCapacity" size="40"
onkeyup="this.value=this.value.replace(/\D/g,'')" onafterpaste="this.value=this.value.replace(/\D/g,'')" />
</div>
</div>
<div class="form-group">
<label class="col-sm-2 control-label">项目默认分支:</label>
<div class="col-sm-8">
<input type="text" class="form-control" id="branch" name="branch" size="40" value="master" />
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-danger" data-dismiss="modal">关闭</button>
<button type="button" class="btn btn-success" value="Validate" onclick="changeOk()">提交</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal -->
</div>
<div class="modal fade" id="myModalMessage" tabindex="-1" role="dialog" style="margin:0 auto;margin-top:20px;width: 480px" aria-labelledby="myModalLabel" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content" style="width: 480px">
<div class="modal-header">
<h4 class="modal-title" id="myModalMessageLabel"></h4>
</div>
<div class="modal-body" style="width: 480px">
<form id="messagehostGroupForm" class="">
<div class="form-group" style="margin-top: -10px">
<textarea id="resultScalingMessage" style="text-align: left; background-color: black; color: white;height:360px;width: 445px;"
readonly="readonly"></textarea>
</div>
</form>
</div>
<div class="modal-footer" style="width: 480px">
<button type="button" class="btn btn-danger" id="closeButton" disabled="disabled" data-dismiss="modal">关闭</button>
</div>
</div>
<!-- /.modal-content -->
</div>
<!-- /.modal -->
</div>
</div>
<script src="<%=basePath%>script/common/genarate_left_panel.js"></script>
<script src="<%=basePath%>script/autoscaling/autoscaling_new.js"></script>
<script>
$("#li_manager").addClass("active open");
$("#li_autoscaling").addClass("active");
</script>
</body>
</html>
<script>
//页面初始化
$(function() {
refreshAutosSalingTable();
});
function changeByCloudType(){
refreshAutosSalingTable();
}
//刷新表格数据
function refreshAutosSalingTable() {
var columns = getColumns();
$("#autoscalingTable").table(
{
columnAutoWidth : false,
url : contextPath + "/autoScalingTool/getAutoScalingGroups?cloudType=" + $("#cloudType").val(),
striped : true,
dataType: "json",
pagination: false,
loadFilter : function(data) {
return defaultLoadFilter(data);
},
columns : columns
});
}
//根据类型获取需要显示的列
function getColumns(){
var columns = [
{
title : "索引",
width : "50px",
formatter : function(value, rowData, rowIndex) {
return (rowIndex + 1);
},
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "组名",
field : "name",
width : "25%",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "主机",
field : "ip",
width : "25%",
formatter : function(value, rowData, rowIndex) {
var instances = rowData.autoScalingHosts;
if(instances == null || instances.length == 0){
return;
}
var ips = "";
for(var index = 0;index < instances.length;index++){
var protectedB = instances[index].protected;
var message = "";
if(protectedB != null && protectedB != undefined){
if(protectedB){
message = "免于缩减";
}
}
if(message != ""){
ips += "<font color='#FF0000'>" + instances[index].ip + ":" + message + "</font>";
}else{
ips += instances[index].ip ;
}
var runningStatusMessage = '-<span class="label label-success">健康</span>';
if("Healthy"!=instances[index].runningStatus){
runningStatusMessage='-<span class="label label-danger">不健康</span>';
}
ips += runningStatusMessage;
ips += "<br>";
}
return ips;
},
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "期望容量",
field : "desired",
width : "50px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "当前容量",
field : "size",
width : "50px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "最少实例数",
field : "min",
width : "75px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "最多实例数",
field : "max",
width : "75px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "操作",
width : "100px",
formatter : function(value, rowData, rowIndex) {
var protectedFromCount=0;
var instances = rowData.autoScalingHosts;
if(instances != null&& instances.length > 0){
for(var index = 0;index < instances.length;index++){
var protectedB = instances[index].protected;
var message = "";
if(protectedB != null && protectedB != undefined){
if(protectedB){
protectedFromCount++; // 免于缩减
}
}
}
}
var div = $("<div>");
$("<button onclick=\"changeServer(\'"
+ rowData.id + "\',\'"
+ rowData.name + "\',\'"
+ protectedFromCount + "\',\'"
+ rowData.desired + "\',\'"
+ rowData.min + "\',\'"
+ rowData.max + "\')\">").addClass(
"btn btn-xs btn-success").html("扩充或缩减")
.appendTo(div);
return div;
},
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
} ];
return columns;
}
</script>
\ No newline at end of file
</html>
\ No newline at end of file
... ...
//页面初始化
$(function() {
refreshAutosSalingTable();
});
function changeByCloudType(){
refreshAutosSalingTable();
}
//刷新表格数据
function refreshAutosSalingTable() {
var columns = getColumns();
$("#autoscalingTable").table(
{
columnAutoWidth : false,
url : contextPath + "autoScalingTool/getAutoScalingGroups?cloudType=" + $("#cloudType").val(),
striped : true,
dataType: "json",
pagination: false,
loadFilter : function(data) {
return defaultLoadFilter(data);
},
columns : columns
});
}
//根据类型获取需要显示的列
function getColumns(){
var columns = [
{
title : "索引",
width : "50px",
formatter : function(value, rowData, rowIndex) {
return (rowIndex + 1);
},
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "组名",
field : "name",
width : "25%",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "主机",
field : "ip",
width : "25%",
formatter : function(value, rowData, rowIndex) {
var instances = rowData.autoScalingHosts;
if(instances == null || instances.length == 0){
return;
}
var ips = "";
for(var index = 0;index < instances.length;index++){
var protectedB = instances[index].protected;
var message = "";
if(protectedB != null && protectedB != undefined){
if(protectedB){
message = "免于缩减";
}
}
if(message != ""){
ips += "<font color='#FF0000'>" + instances[index].ip + ":" + message + "</font>";
}else{
ips += instances[index].ip ;
}
var runningStatusMessage = '-<span class="label label-success">健康</span>';
if("Healthy"!=instances[index].runningStatus){
runningStatusMessage='-<span class="label label-danger">不健康</span>';
}
ips += runningStatusMessage;
ips += "<br>";
}
return ips;
},
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "期望容量",
field : "desired",
width : "50px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "当前容量",
field : "size",
width : "50px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "最少实例数",
field : "min",
width : "75px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "最多实例数",
field : "max",
width : "75px",
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
},
{
title : "操作",
width : "100px",
formatter : function(value, rowData, rowIndex) {
var protectedFromCount=0;
var instances = rowData.autoScalingHosts;
if(instances != null&& instances.length > 0){
for(var index = 0;index < instances.length;index++){
var protectedB = instances[index].protected;
var message = "";
if(protectedB != null && protectedB != undefined){
if(protectedB){
protectedFromCount++; // 免于缩减
}
}
}
}
var div = $("<div>");
$("<button onclick=\"changeServer(\'"
+ rowData.id + "\',\'"
+ rowData.name + "\',\'"
+ protectedFromCount + "\',\'"
+ rowData.desired + "\',\'"
+ rowData.min + "\',\'"
+ rowData.max + "\')\">").addClass(
"btn btn-xs btn-success").html("扩充或缩减")
.appendTo(div);
return div;
},
styler : function(value, rowData, rowIndex){
return {
"vertical-align" : "middle"
};
}
} ];
return columns;
}
//修改前原始数据,用于判断是否需要调用修改接口
var scalingGroupName;
var souScalingGroupId;
var souProtectedFromCount;
var souDesiredCapacity;
var souMinSize;
var souMaxSize;
//需要发布的版本
var souBranch;
//修改伸缩组
function changeServer(scalingGroupId, groupName, protectedFromCount, desiredCapacity, minSize, maxSize){
scalingGroupName = groupName;
souScalingGroupId = scalingGroupId;
souProtectedFromCount = protectedFromCount;
souDesiredCapacity = desiredCapacity;
//souDesiredCapacity = 2;
souMinSize = minSize;
souMaxSize = maxSize;
$("#myModalLabel").text("");
$("#protectedFromCount").val("");
$("#minSize").val("");
$("#maxSize").val("");
$("#desiredCapacity").val("");
$("#myModalLabel").text(groupName + " : 扩充或缩减");
$("#protectedFromCount").val(protectedFromCount);
$("#minSize").val(minSize);
$("#maxSize").val(maxSize);
$("#desiredCapacity").val(desiredCapacity);
$("#myModal").modal('show');
}
function changeOk(){
//分支版本
souBranch = $("#branch").val();
if(souBranch == "" || souBranch == undefined){
alert("需要发布的分支版本不能为空");
return;
}
//异常处理
if(souScalingGroupId == "" || souScalingGroupId == undefined
|| souProtectedFromCount == "" || souProtectedFromCount == undefined
|| souMinSize == "" || souMinSize == undefined
|| souMaxSize == "" || souMaxSize == undefined
|| souDesiredCapacity == "" || souDesiredCapacity == undefined){
alert("异常,请重新点击 扩充或缩减 开始");
return;
}
//受保护的实例数
var protectedFromCount = $("#protectedFromCount").val();
//最少实例数,大于等于受保护的实例数
var minSize = $("#minSize").val();
//最多实例数
var maxSize = $("#maxSize").val();
//期望实例数,大于等于最小实例数 小于等于最多实例数
var desiredCapacity = $("#desiredCapacity").val();
if((protectedFromCount == souProtectedFromCount) && (minSize == souMinSize)
&& (maxSize == souMaxSize)
&& (desiredCapacity == souDesiredCapacity)){
alert("数据未做修改!");
$("#myModal").modal('hide');
return;
}
if(minSize < protectedFromCount){
alert("期望调整的最小实例数 小于 受保护的实例数!");
return;
}else if(maxSize < minSize){
alert("期望调整的最大实例数 小于 最小实例数!");
return;
}else if((desiredCapacity < minSize) || (desiredCapacity > maxSize)){
alert("期望调整的容量必须在最小和最大实例数之间,最大<=容量>=最小!");
return;
}
var showMessage;
if(desiredCapacity == souDesiredCapacity){
//基础信息修改,不涉及到缩容或者扩容
showMessage = "";
}else{
if(desiredCapacity < souDesiredCapacity){
showMessage = "缩容";
}else if(desiredCapacity > souDesiredCapacity){
showMessage = "扩容";
}
}
if(confirm("是否确定要执行!")){
$("#myModal").modal('hide');
var parms = {};
if(2 != $("#cloudType").val()){
alert("暂时只提供腾讯云的操作!");
return;
}else{
var qCloudParms = {};
parms.cloudType = parseInt($("#cloudType").val());
qCloudParms.scalingGroupId = souScalingGroupId;
qCloudParms.minSize = parseInt(minSize);
qCloudParms.maxSize = parseInt(maxSize);
qCloudParms.desiredCapacity = parseInt(desiredCapacity);
parms.qCloudParms = qCloudParms;
}
$.ajax({
url: contextPath + 'autoScalingTool/modifyScalingGroup?cloudType=' + parseInt($("#cloudType").val()),
type: 'POST',
data: qCloudParms,
dataType: 'json',
success: function (data) {
if (!data || data.code != 200) {
alert('修改伸缩组失败:'+data.message);
}else{
if(showMessage == "" || showMessage == undefined){
alert("修改基础信息成功!");
clear_Sour();
return;
}
$("#myModalMessageLabel").text(scalingGroupName + ":正在 " + showMessage);
$("#myModalMessage").modal('show');
$("#myModalMessage").unbind("keyup");
$(".modal-backdrop").unbind("click");
//清空
$("#resultScalingMessage").html("");
$("#closeButton").attr("disabled","disabled");
//1:开始伸缩通知,成功扩容后才能执行下一步
refCloudMessage(showMessage, Math.abs(souDesiredCapacity - desiredCapacity));
}
},
error: function (e) {
alert('系统异常');
clear_Sour();
}
});
}
}
function clear_Sour(){
//清空
souProtectedFromCount = "";
souDesiredCapacity = "";
souMinSize = "";
souMaxSize = "";
}
//腾讯云:修改伸缩组后的下一个流程是查询伸缩活动
function refCloudMessage(showMessage, serverCount){
var timestamp = Date.parse(new Date());
var count = 0;
var url = contextPath + 'autoScalingTool/describeScalingActivity?scalingGroupId=' + souScalingGroupId + '&startTime=' + timestamp;
writeToText("开始..........");
var intervalIndex = setInterval(function() {
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
success: function (data) {
if (!data || data.code != 200) {
responseError(data);
}else{
var dataJson = data.data[0];
if(dataJson.succInsList == undefined || dataJson.succInsList.length != serverCount){
if(count == 0){
writeToText(dataJson.desciption);
}else{
writeToText("......");
}
}else{
writeToText("第 1 步:" + showMessage + " 成功!");
writeToText("...");
clearInterval(intervalIndex);
if(showMessage == "缩容"){
unDeploy(showMessage);
writeToText("结束..........");
return;
}else{
//扩容成功后执行
deploy(dataJson.succInsList);
}
}
}
count += 1;
},
error: function (e) {
requestError(url);
}
});
}, 10000);
}
//写入消息
function writeToText(msg){
var d = $("#resultScalingMessage").val();
$("#resultScalingMessage").html(d + "&#13" + msg);
var scrollTop = $("#resultScalingMessage")[0].scrollHeight;
$("#resultScalingMessage").scrollTop(scrollTop);
}
//1:扩容成功后执行
function deploy(instanceIds){
if(instanceIds == undefined){
//发布完之后,显示关闭按钮
$("#closeButton").removeAttr("disabled");
return;
}
var instanceIdStr = "";
for (var i = 0; i < instanceIds.length; i ++) {
if(i == instanceIds.length - 1){
instanceIdStr += instanceIds[i];
}else{
instanceIdStr += instanceIds[i] + ",";
}
}
writeToText("实例ID为:" + instanceIdStr);
writeToText(">>>正在通过实例ID获取实例的内网ip:请稍后...");
//2:根据实例id获取内网ip地址
var ips = getIpByInstanceIds(instanceIdStr);
writeToText("第 2 步:获取内网成功!");
if(ips == undefined || ips == null || ips == ""){
writeToText("系统异常,执行失败....");
deployLaster();
return;
}
writeToText(">>>正在部署系统,请稍后...");
if(scalingGroupName.indexOf("nginx")){
$.ajax({
url: contextPath + "nginxSync/pushTask",
type: "post",
dataType: "json",
data: {
type: 1,
select: $("#cloudType").val()
},
success: function (response) {
var intervalNginx = setInterval(function () {
$.ajax({
url: contextPath + "nginxSync/getTaskLog",
type: 'POST',
dataType: 'json',
data: {
taskId: response.data.taskId
},
success: function (data3) {
//console.log(data3);
var messagedata = data3.data;
var logList = messagedata.log;
if (logList != "") {
writeToText(logList);
}
//code为2 ,则结束
var code = messagedata.isFinished;
if (code == 1) {
clearInterval(intervalNginx);
writeToText("完毕..........");
}
},
error: function (e) {
requestError(url);
}
});
}, 3000);
},
error: function (e) {
requestError(url);
}
});
}else{
//3:根据ip部署项目,得到消息id
var messageId = deployProject(ips);
writeToText("第 3 步:项目正在部署!")
//3.1:发布项目的同时获取发布的消息,由于定时器是异步行为,故下一步骤智能在内部进行
deployProjectGetMsg(messageId,ips);
}
}
//发布成功和失败都执行
function deployLaster(){
//发布完之后,显示关闭按钮
$("#closeButton").removeAttr("disabled");
//成功后清空
clear_Sour();
}
//2:根据实例id获取内网ip地址
function getIpByInstanceIds(instanceIds){
var returnIps = "";
var url = contextPath + 'autoScalingTool/getQcloudDescribeInstances?ids=' + instanceIds;
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
async: false,
success: function (data) {
if (!data || data.code != 200) {
responseError(data);
}else{
//组装内网ip
var dataJson = data.data;
if(dataJson == undefined){
writeToText("系统异常,执行失败....");
//发布完之后,显示关闭按钮
$("#closeButton").removeAttr("disabled");
return;
}
//展现
var ips = "";
for(var i = 0;i < dataJson.length;i++){
if(i == dataJson.length - 1){
ips += dataJson[i].lanIp;
}else{
ips += dataJson[i].lanIp + ",";
}
writeToText("实例id:" + dataJson[i].unInstanceId + " - ip:" + dataJson[i].lanIp);
}
returnIps = ips;
}
},
error: function (e) {
requestError(url);
}
});
return returnIps;
}
//3:根据ip部署项目,返回部署的消息id,同步获取部署的进展
function deployProject(ips){
var returnMessageId = "";
var url = contextPath + 'autoScalingTool/deployCloudProject?projectName='+scalingGroupName+'&ips='+ips+'&branch=' + souBranch + '&environment=qcloud';
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
async: false,
success: function (data) {
if (!data || data.code != 200) {
responseError(data);
}else{
returnMessageId = data.data.messageids.split(',')[0];
}
},
error: function (e) {
requestError(url);
}
});
return returnMessageId;
}
//3.1:发布项目的同时获取发布的消息
function deployProjectGetMsg(msgId, ips){
var intervalIndexMsg = setInterval(function() {
var url = contextPath + 'project/getbuildmsg?messageid=' + msgId+"&project="+scalingGroupName;
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
success: function (data3) {
var obj2 = eval("(" + data3 + ")");
var messagedata = obj2.data;
if ((messagedata.message != "") && (messagedata.message != null) && (messagedata.message != undefined)) {
writeToText(messagedata.message);
}
//code为2 ,则结束
var code = obj2.code;
//只有状态2,3,4才表示系统部署成功与否
if (code == 2 || code == 3 || code == 4) {
writeToText("第 3 步:系统部署成功!");
clearInterval(intervalIndexMsg);
writeToText(">>>正在进行集成测试,请稍后...");
//4:集成测试
integrationTest(ips);
}
},
error: function (e) {
requestError(url);
clearInterval(intervalIndexMsg);
}
});
}, 3000);
}
//4:集成测试
function integrationTest(ips){
var url = contextPath + 'autoScalingTool/integrationTest?cloudType='+$("#cloudType").val()+'&projectName='+scalingGroupName+'&ips='+ips;
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
async: false,
success: function (data) {
if (!data || data.code != 200) {
responseError(data);
}else{
writeToText(" ");
var dataJson = data.data;
for (var i = 0; i < dataJson.length; i ++) {
writeToText(dataJson[i].ip + ":请求url:" + dataJson[i].url);
var state = dataJson[i].state;
var stateMsg;
if(state == 200){
stateMsg = "成功访问";
writeToText("状态为:" + state + " - " + stateMsg);
writeToText("第 4 步:集成测试完毕!");
writeToText(">>>正在更新git-iptables,请稍后...");
//5:更新git文件
editToGit();
}else{
stateMsg = "访问失败";
writeToText("状态为:" + state + " - " + stateMsg);
deployLaster();
}
}
}
},
error: function (e) {
requestError(url);
}
});
}
//5:ip写入git
function editToGit(showMessage){
var url = contextPath+'autoScalingTool/updateIpToGit?cloudType='+$("#cloudType").val()+'&projectName='+scalingGroupName+'&scalingGroupId=' + souScalingGroupId;
$.ajax({
url: url,
type: 'POST',
dataType: 'json',
async: false,
success: function (data) {
if (!data || data.code != 200) {
responseError(data);
}else{
writeToText(" ");
writeToText("更新之后的ip集合是:"+data.message);
if(showMessage != null && showMessage != undefined){
writeToText("更新git - app-iptable文件成功!");
}else{
writeToText("第 5 步:更新git - app-iptable文件成功!");
}
//扩容成功后刷新数据
refreshAutosSalingTable();
//部署全部成功后执行
deployLaster();
writeToText("完毕..........");
}
},
error: function (e) {
requestError(url);
}
});
}
//缩容成功后执行
function unDeploy(showMessage){
writeToText("正在更新git-iptables,请稍后...");
//5:更新git文件
editToGit(showMessage);
//发布完之后,显示关闭按钮
$("#closeButton").removeAttr("disabled");
//成功后清空
clear_Sour();
}
//请求接口异常
function requestError(api){
writeToText('系统异常:' + api);
deployLaster();
}
//接口返回异常
function responseError(data){
if(!data){
writeToText('返回数据异常:data为空');
}else{
writeToText('返回数据异常:code=' + data.code + ',message=' + data.message);
}
deployLaster();
}
... ...