From bd63d4b4bba089fc6c7ed8b77173a77e521c41b5 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Mon, 30 Jul 2012 10:43:17 -0700 Subject: [PATCH 1/8] Fix positioning of tags error labels --- ui/css/cloudstack3.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index fe0a5028d39..3791da46a3a 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -9009,8 +9009,8 @@ div.panel.ui-dialog div.list-view div.fixed-header { .tagger form label.error { position: absolute; color: #FF0000; - left: 42px; - top: 29px; + left: 44px; + top: 28px !important; /*[empty]background-color:;*/ } From d467ff8a494cfaa304a66ba866c3e73695a0aa12 Mon Sep 17 00:00:00 2001 From: Alena Prokharchyk Date: Mon, 30 Jul 2012 10:46:09 -0700 Subject: [PATCH 2/8] CS-15743: disable static nat as a part of network resources cleanup --- .../com/cloud/network/NetworkManagerImpl.java | 5 ++ .../com/cloud/network/rules/RulesManager.java | 9 +++ .../cloud/network/rules/RulesManagerImpl.java | 67 ++++++++++++++----- 3 files changed, 65 insertions(+), 16 deletions(-) diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 46896c83f99..8c855af2ff2 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -6186,6 +6186,11 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag success = false; } + //release all static nats for the network + if (!_rulesMgr.applyStaticNatForNetwork(networkId, false, caller, true)) { + s_logger.warn("Failed to disable static nats as part of shutdownNetworkRules for network id " + networkId); + success = false; + } // Get all ip addresses, mark as releasing and release them on the backend Network network = getNetwork(networkId); diff --git a/server/src/com/cloud/network/rules/RulesManager.java b/server/src/com/cloud/network/rules/RulesManager.java index a188bd1e776..bff3a115cc1 100644 --- a/server/src/com/cloud/network/rules/RulesManager.java +++ b/server/src/com/cloud/network/rules/RulesManager.java @@ -74,4 +74,13 @@ public interface RulesManager extends RulesService { boolean disableStaticNat(long ipAddressId, Account caller, long callerUserId, boolean releaseIpIfElastic) throws ResourceUnavailableException; + /** + * @param networkId + * @param continueOnError + * @param caller + * @param forRevoke + * @return + */ + boolean applyStaticNatForNetwork(long networkId, boolean continueOnError, Account caller, boolean forRevoke); + } diff --git a/server/src/com/cloud/network/rules/RulesManagerImpl.java b/server/src/com/cloud/network/rules/RulesManagerImpl.java index 658f4931745..140d0366ebd 100755 --- a/server/src/com/cloud/network/rules/RulesManagerImpl.java +++ b/server/src/com/cloud/network/rules/RulesManagerImpl.java @@ -1293,13 +1293,58 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { @Override public boolean applyStaticNatForIp(long sourceIpId, boolean continueOnError, Account caller, boolean forRevoke) { - - List staticNats = new ArrayList(); IpAddress sourceIp = _ipAddressDao.findById(sourceIpId); + + List staticNats = createStaticNatForIp(sourceIp, caller, forRevoke); + if (staticNats != null && !staticNats.isEmpty()) { + try { + if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) { + return false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to create static nat rule due to ", ex); + return false; + } + } + + return true; + } + + + @Override + public boolean applyStaticNatForNetwork(long networkId, boolean continueOnError, Account caller, boolean forRevoke) { + List staticNatIps = _ipAddressDao.listStaticNatPublicIps(networkId); + + List staticNats = new ArrayList(); + for (IpAddress staticNatIp : staticNatIps) { + staticNats.addAll(createStaticNatForIp(staticNatIp, caller, forRevoke)); + } + + if (staticNats != null && !staticNats.isEmpty()) { + if (forRevoke) { + s_logger.debug("Found " + staticNats.size() + " static nats to disable for network id " + networkId); + } + try { + if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) { + return false; + } + } catch (ResourceUnavailableException ex) { + s_logger.warn("Failed to create static nat rule due to ", ex); + return false; + } + } else { + s_logger.debug("Found 0 static nat rules to apply for network id " + networkId); + } + + return true; + } + + protected List createStaticNatForIp(IpAddress sourceIp, Account caller, boolean forRevoke) { + List staticNats = new ArrayList(); if (!sourceIp.isOneToOneNat()) { - s_logger.debug("Source ip id=" + sourceIpId + " is not one to one nat"); - return true; + s_logger.debug("Source ip id=" + sourceIp + " is not one to one nat"); + return staticNats; } Long networkId = sourceIp.getAssociatedWithNetworkId(); @@ -1330,19 +1375,9 @@ public class RulesManagerImpl implements RulesManager, RulesService, Manager { } StaticNatImpl staticNat = new StaticNatImpl(sourceIp.getAllocatedToAccountId(), sourceIp.getAllocatedInDomainId(), - networkId, sourceIpId, dstIp, forRevoke); + networkId, sourceIp.getId(), dstIp, forRevoke); staticNats.add(staticNat); - - try { - if (!_networkMgr.applyStaticNats(staticNats, continueOnError)) { - return false; - } - } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to create static nat rule due to ", ex); - return false; - } - - return true; + return staticNats; } @Override From c11aab3c7e43c15e6292855ec82aac8efb347c69 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Mon, 30 Jul 2012 11:02:23 -0700 Subject: [PATCH 3/8] Merge Autoscaler UI implemetation This change includes the new dialog box for the CloudStack Autoscaler implementation. It is accessible by a button ('Autoscaler') that appears under each LB rule. This also contains changes to the multiEdit widget to support features required for Autoscaler: -Fixes context/data passing to custom button widgets -Fixes data retrieval for select fields --- ui/css/cloudstack3.css | 223 ++++++ ui/images/minus.png | Bin 0 -> 1544 bytes ui/index.jsp | 2 + ui/scripts/autoscaler.js | 1038 ++++++++++++++++++++++++++++ ui/scripts/network.js | 20 +- ui/scripts/ui-custom/autoscaler.js | 278 ++++++++ ui/scripts/ui/widgets/multiEdit.js | 33 +- 7 files changed, 1584 insertions(+), 10 deletions(-) create mode 100644 ui/images/minus.png create mode 100644 ui/scripts/autoscaler.js create mode 100644 ui/scripts/ui-custom/autoscaler.js diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 3791da46a3a..f63057c58d0 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -9634,6 +9634,229 @@ div.panel.ui-dialog div.list-view div.fixed-header { overflow: auto; } +/*Autoscaler*/ +.ui-dialog div.autoscaler { + overflow: auto; + max-height: 600px; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=securityGroups] { + display: block; + width: 370px; + float: left; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=diskOfferingId] { + display: inline-block; + width: 370px; + float: left; + position: relative; + margin-top: 1px; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=minInstance] { + display: block; + width: 50%; + float: left; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=maxInstance] { + display: inline-block; + width: 50%; + float: left; + left: -30px; + position: relative; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=interval] { + display: block; + width: 50%; + float: left; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=quietTime] { + display: inline-block; + width: 50%; + float: left; + left: -15px; + position: relative; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=snmpCommunity] { + display: block; + width: 50%; + float: left; +} + +.ui-dialog div.autoscaler div.form-container div.form-item[rel=snmpPort] { + display: inline-block; + width: 50%; + float: left; + left: -15px; + position: relative; +} + +.ui-dialog div.autoscaler div.form-container div.value select { + width: 88%; + float: left; +} + +div.ui-dialog div.autoscaler div.scale-up-policy-title div.form-container { + height: 55px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy-title div.form-container { + height: 55px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy div.multi-edit { + margin-top: 0px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy div.multi-edit { + margin-top: 0px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy-title { + color: #0055BB; + margin-left: -650px; + margin-top: 40px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy-title label { + font-size: 13px; + margin-left: 200px; + margin-right: 10px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy-title hr.policy-divider { + border-left: 1px none #38546D; + border-right: 1px none #16222C; + border-top: 1px none #38546D; + margin-bottom: 12px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy-title hr.policy-divider { + border-left: 1px none #38546D; + border-right: 1px none #16222C; + border-top: 1px none #38546D; + margin-bottom: 12px; +} + +div.ui-dialog div.autoscaler div.field-group.bottom-fields hr.policy-divider { + border-left: 1px none #38546D; + border-right: 1px none #16222C; + border-top: 1px none #38546D; + margin-top: 15px; + margin-bottom: -1px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy-title label { + font-size: 13px; + margin-left: 170px; + margin-right: 10px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy-title { + color: #0055BB; + margin-left: -620px; + margin-top: 10px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy-title div.form-container div.form-item div.value input[type=text] { + margin-left: 195px; + width: 30%; + margin-top: 1px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy-title div.form-container div.form-item div.name { + margin-left: 390px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy-title div.form-container div.form-item div.value input[type=text] { + margin-left: 670px; + width: 30%; + margin-top: -16px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy-title div.form-container div.form-item div.name { + margin-left: 390px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy div.multi-edit div.data div.data-body div.data-item { + margin-bottom: 0px; + margin-right: 22px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy div.multi-edit div.data div.data-body div.data-item { + margin-bottom: 0px; + margin-right: 22px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy div.slide-label { + color: #A5A3A7; + font-size: 14px; + margin-bottom: 3px; + margin-left: 755px; + width: 12px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy div.slide-label { + color: #A5A3A7; + font-size: 14px; + margin-bottom: 3px; + margin-left: 755px; + width: 12px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy div.hide { + background: #FFFFFF url("../images/minus.png") no-repeat 38% 59%; + border: 1px solid #D0D0D0; + border-radius: 9px 9px 9px 9px; + cursor: pointer; + float: right; + height: 15px; + margin: -20px 45px 0 11px; + width: 14px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy div.hide { + background: #FFFFFF url("../images/minus.png") no-repeat 31% 54%; + border: 1px solid #D0D0D0; + border-radius: 9px 9px 9px 9px; + cursor: pointer; + float: right; + height: 15px; + margin: -20px 45px 0 11px; + width: 14px; +} + +div.ui-dialog div.autoscaler div.scale-up-policy div.expand { + background: #FFFFFF url("../images/sprites.png") repeat -541px -499px; + border: 1px solid #D0D0D0; + border-radius: 9px 9px 9px 9px; + cursor: pointer; + float: right; + height: 15px; + margin: -20px 45px 0 11px; + width: 14px; +} + +div.ui-dialog div.autoscaler div.scale-down-policy div.expand { + background: #FFFFFF url("../images/sprites.png") repeat -541px -499px; + border: 1px solid #D0D0D0; + border-radius: 9px 9px 9px 9px; + cursor: pointer; + float: right; + height: 15px; + margin: -20px 45px 0 11px; + width: 14px; +} + +div.ui-dialog div.autoscaler div.field-group div.form-container form div.form-item div.name label { + font-size: 11px; +} + /*Action icons*/ .action.edit .icon { background-position: 1px -1px; diff --git a/ui/images/minus.png b/ui/images/minus.png new file mode 100644 index 0000000000000000000000000000000000000000..077db991d49f62a1753d824ed9861d9057505fec GIT binary patch literal 1544 zcmeAS@N?(olHy`uVBq!ia0vp^!ayv-!3HGrL)l7zlw^r(L`iUdT1k0gQ7VIDN`6wR zf@f}GdTLN=VoGJ<$y6H#2IjQPkcg59UmvUF{9L_6kQ%*;+ybC(1_m4Zih{)C?9>v4 zq}24xJX@vryZ0+8WTx0Eg`4^s_!c;)W@LI)6{QAO`Gq7`WhYyvDB0U7*i={n4aiL` zNmQuF&B-gas<2f8n`;GRgM{^!6u?SKvTcwn`GuBNuFf>#!Gt)CP zF*P$Y)KM@pFf`IP03tJ8LlY}gGb`4?pZBPB7%B|o_|H#M)s)5TT^D5IB>nPO#RXzXTc z=;-F`=Szfw1DjrRV`oDbCsR`w6DLbULsvs5CrdLY zV>2gb0~1qAXG>$4UeCPZlEl2^RG7V)KzpHjP4McqaxO|uEXgkl$G8yO;GeeeCv{0lv$RV;#QQOs{jsPt4u8Rn^+h-x)_@~ySU); zH$-m=Ibo&`bc{YIaUdlYm=G`pf|&5659GizPih`8#}omx2CLk09|i^{3r`ovkcwMd zLVWXXIf&HVNXTLKWLP;dXh~k=Ay$rTKA}R+cY>~GWj8%ykWol!zQSr2nmTj7lEI2^ zKiFsNGw;&%@XB8KR^7JR#`yi`-{%X?J&afUeE;ONbIaZtU;9{lEvd(}VD+-BSxZ;G z;@-zTN#(n~zE}J|k8Ke;yG}p-v@S-^yfl_wsOfp7Q`lHg!t6*zuaUXZ-^ur2Y;+_T%t*UZ;>_PKI;M}^mnWha+k))XxBKM|I_+)k=@ zUVZw-=$6D2f$i(By-rtIBi!$@?$?>u0X-tFo^yA`=&@hT61BOW`zXEr8;fLeoi?Az z!vc#rs+M+_O?aCWmZWyeMJCQXFJ*Z1`EmCRI?;b_ewElK+ObF=B~qxm{jc1uw_;oJ z^IezK-dEb{<|O7C*sCYBuWoa~;~d9nDkoNJUD&4ce1lHRjkk3R-fXDZ*S-5@&a{%u zNbeI9P8>Sx@ABj0Gd8YPrMM}IJjxH*BELTTC8eU-JdLHGG*m3biw8k1YzmUVwkD?0Nmc#<#A69!L~on7l>)gSA=(Bb2J`Q&qD6yKzr zRkLm#HDJPJh2)*X)ofg?}{cRGvtcoet0!kuTu6yL?8v-`(Q9eiCfz qpLN!2=+BCiI8k(}@|*b&%>xXvf{7ge4Zqui%4SbjKbLh*2~7Zo3_el- literal 0 HcmV?d00001 diff --git a/ui/index.jsp b/ui/index.jsp index 3cb2b6c5bcb..c7418b76c33 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -1624,6 +1624,8 @@ + + diff --git a/ui/scripts/autoscaler.js b/ui/scripts/autoscaler.js new file mode 100644 index 00000000000..72876b1a291 --- /dev/null +++ b/ui/scripts/autoscaler.js @@ -0,0 +1,1038 @@ +// Copyright 2012 Citrix Systems, Inc. Licensed under the +// Apache License, Version 2.0 (the "License"); you may not use this +// file except in compliance with the License. Citrix Systems, Inc. +// reserves all rights not expressly granted by the License. +// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// +// Automatically generated by addcopyright.py at 04/03/2012 +(function($,cloudstack) { + var scaleUpData = []; + var totalScaleUpCondition = 0; + var scaleDownData = []; + var totalScaleDownCondition = 0; + + cloudStack.autoscaler = { + dataProvider: function(args) { + // Reset data + scaleUpData = []; + totalScaleUpCondition = 0; + scaleDownData = []; + totalScaleDownCondition = 0; + + var sampleData = null; + /* + var sampleData = { + templateNames: '58d3f4b2-e847-4f93-993d-1ab1505129b6', //(will set this value to dropdown) + serviceOfferingId: '4aa823f3-27ec-46af-9e07-b023d7a7a6f1', //(will set this value to dropdown) + minInstance: 1, + maxInstance: 10, + scaleUpPolicy: { + id: 12345, + duration: 1000, + conditions: [ + { + id: 1, + counterid: 'cpu', + relationaloperator: "GE", + threshold: 100 + }, + { + id: 2, + counterid: 'memory', + relationaloperator: "LT", + threshold: 200 + } + + ] + }, + scaleDownPolicy: { + id: 6789, + duration: 500, + conditions: [ + { + id: 1, + counterid: 'cpu', + relationaloperator: "LT", + threshold: 30 + }, + { + id: 2, + counterid: 'cpu', + relationaloperator: "LT", + threshold: 50 + } + + ] + }, + interval: 200, + quietTime: 300, + destroyVMgracePeriod: null, + securityGroups: null, // (will set this value to dropdown) + diskOfferingId: 'a21c9aa4-ef7e-41dd-91eb-70b2182816b0', // (will set this value to dropdown) + snmpCommunity: 1, + snmpPort: 225, + + isAdvanced: false // Set this to true if any advanced field data is present + }; + */ + + args.response.success({ data: sampleData }); + }, + + // -- + // Add the following object blocks: + // + // topFields: { } + // bottomFields: { }, + // scaleUpPolicy: { }, + // scaleDownPolicy: { } + // -- + // + forms: { + topFields: { + //** + //** Disabled due to UI issues + //** + // templateCategory: { + // label: 'Template', + // id: 'templatecategory', + // select: function(args) { + // args.response.success({ + // data: [ + // { id: 'all', description: _l('ui.listView.filters.all') }, + // { id: 'featured', description: _l('label.featured') }, + // { id: 'Community', description: _l('label.menu.community.templates') }, + // { id: 'self', description: _l('ui.listView.filters.mine') } + // ] + // }); + // } + // }, + //** + + templateNames: { + label: 'label.template', + id: 'templatename', + select: function(args) { + var templates; + var templateIdMap = {}; + $.ajax({ + url: createURL('listTemplates'), + data: { + templatefilter: 'featured', + zoneid: args.context.networks[0].zoneid + }, + async: false, + success: function(json) { + templates = json.listtemplatesresponse.template; + if (templates == null) + templates = []; + $(templates).each(function() { + templateIdMap[this.id] = 1; + }); + } + }); + + $.ajax({ + url: createURL('listTemplates'), + data: { + templatefilter: 'community', + zoneid: args.context.networks[0].zoneid + }, + async: false, + success: function(json) { + var items = json.listtemplatesresponse.template; + $(items).each(function() { + if(!(this.id in templateIdMap)) { + templates.push(this); + templateIdMap[this.id] = 1; + } + }); + } + }); + + $.ajax({ + url: createURL('listTemplates'), + data: { + templatefilter: 'selfexecutable', + zoneid: args.context.networks[0].zoneid + }, + async: false, + success: function(json) { + var items = json.listtemplatesresponse.template; + $(items).each(function() { + if(!(this.id in templateIdMap)) { + templates.push(this); + templateIdMap[this.id] = 1; + } + }); + } + }); + + args.response.success({ + data: $.map(templates, function(template) { + return { + id: template.id, + description: template.name + }; + }) + }); + } + }, + + serviceOfferingId: { + label: 'label.compute.offering', + select: function(args) { + $.ajax({ + url: createURL("listServiceOfferings&issystem=false"), + dataType: "json", + async: true, + success: function(json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + args.response.success({ + data: $.map(serviceofferings, function(serviceoffering) { + return { + id: serviceoffering.id, + description: serviceoffering.name + }; + }) + }); + } + }); + } + }, + + minInstance: { + label: 'Min Instances', + defaultValue: '3', + validation: { required: true } + }, + + maxInstance: { + label: 'Max Instances', + defaultValue: '10', + validation: { required: true } + } + }, + + bottomFields: { + isAdvanced: { isBoolean: true, label: 'Show advanced settings' }, + interval: { + label: 'Polling Interval (in sec)', + defaultValue: '30', + validation: { required: true } + }, + + quietTime: { + label: 'Quiet Time (in sec)', + defaultValue: '300', + validation: { required: true } + }, + + destroyVMgracePeriod: { + label: 'Destroy VM Grace Period', + defaultValue: '30', + isHidden:true, + dependsOn:'isAdvanced', + validation: { required: true } + }, + securityGroups: { + label: 'label.menu.security.groups', + isHidden: true, + dependsOn: 'isAdvanced', + select: function(args) { + $.ajax({ + url: createURL("listSecurityGroups&listAll=true"), + dataType: "json", + async: true, + success: function(json) { + var securitygroups = json.listsecuritygroupsresponse.securitygroup; + var items = []; + items.push({id: "", description: ""}); + $(securitygroups).each(function(){ + items.push({id: this.id, description: this.name}); + }); + args.response.success({ data: items }); + } + }); + } + }, + + diskOfferingId: { + label: 'label.menu.disk.offerings', + isHidden: true, + dependsOn: 'isAdvanced', + select: function(args) { + $.ajax({ + url: createURL("listDiskOfferings&listAll=true"), + dataType: "json", + async: true, + success: function(json) { + var diskofferings = json.listdiskofferingsresponse.diskoffering; + var items = []; + items.push({id: "", description: ""}); + $(diskofferings).each(function(){ + items.push({id: this.id, description: this.name}); + }); + args.response.success({ data: items }); + } + }); + } + }, + + snmpCommunity: { + isHidden: true, + dependsOn: 'isAdvanced', + label: 'SNMP Community', + defaultValue: 'public', + validation: { required: true } + }, + + snmpPort: { + isHidden: true, + dependsOn: 'isAdvanced', + label: 'SNMP Port', + defaultValue: '161', + validation: { required: true } + }, + + username: { + isHidden: true, + dependsOn: 'isAdvanced', + label: 'User', + select: function(args) { + var items = []; + if(isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL('listUsers'), + data: { + domainid: g_domainid, + account: g_account + }, + success: function(json) { + var users = json.listusersresponse.user; + $(users).each(function(){ + items.push({id: this.id, description: this.username}); + }); + args.response.success({ data: items }); + } + }); + } + else { //regular user doesn't have access to listUers API call. + items.push({id: "", description: ""}); + } + } + } + }, + scaleUpPolicy: { + title: 'ScaleUp Policy', + label: 'SCALE UP POLICY', + noSelect: true, + noHeaderActionsColumn: true, + ignoreEmptyFields: true, + fields: { + 'counterid': { + label: 'Counter', + select: function(args) { + $.ajax({ + url: createURL("listCounters"), + dataType: "json", + async: true, + success: function(json) { + var counters = json.counterresponse.counter; + + args.response.success({ + data: $.map(counters, function(counter) { + return { + name: counter.id, + description: counter.name + }; + }) + }); + } + }); + } + }, + 'relationaloperator': { + label: 'Operator', + select: function(args) { + args.response.success({ + data: [ + { name: 'GT', description: 'greater-than' }, + { name: 'GE', description: 'greater-than or equals to' }, + { name: 'LT', description: 'less-than' }, + { name: 'LE', description: 'less-than or equals to' }, + { name: 'EQ', description: 'equals-to' } + ] + }); + } + }, + 'threshold': { edit: true, label: 'Threshold' }, + 'add-scaleUpcondition': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + scaleUpData.push($.extend(args.data, { + index: totalScaleUpCondition + })); + + totalScaleUpCondition++; + args.response.success(); + } + }, + actions: { + destroy: { + label: '', + action: function(args) { + scaleUpData = $.grep(scaleUpData, function(item) { + return item.index != args.context.multiRule[0].index; + }); + totalScaleUpCondition--; + args.response.success(); + } + } + }, + dataProvider: function(args) { + var data = scaleUpData; + var $autoscaler = $('.ui-dialog .autoscaler'); + var initialData = $autoscaler.data('autoscaler-scale-up-data'); + + if ($.isArray(initialData)) { + $(initialData).each(function() { + this.index = totalScaleUpCondition; + totalScaleUpCondition++; + scaleUpData.push(this); + }); + + $autoscaler.data('autoscaler-scale-up-data', null); + } + + args.response.success({ + data: scaleUpData + }); + } + /*actions: { + destroy: { + label: '', + action: function(args) { + $.ajax({ + url: createURL("deleteCondition&id=" + args.context.multiRule[0].counterid), + dataType: 'json', + async: true, + success: function(data) { + var jobId = data.deleteconditionresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + } + }); + } + }); + } + } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listConditions'), + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.map( + data.listconditionsresponse.condition ? + data.listconditionsresponse.condition : [], + function(elem) { + return { + counterid: elem.id, + relationaloperator: elem.relationaloperator, + threshold: elem.threshold + }; + } + ) + }); + } + }); + }*/ + }, + + scaleDownPolicy: { + title: 'ScaleDown Policy', + noSelect: true, + noHeaderActionsColumn: true, + ignoreEmptyFields: true, + fields: { + 'counterid': { + label: 'Counter', + select: function(args) { + $.ajax({ + url: createURL("listCounters"), + dataType: "json", + async: true, + success: function(json) { + var counters = json.counterresponse.counter; + + args.response.success({ + data: $.map(counters, function(counter) { + return { + name: counter.id, + description: counter.name + }; + }) + }); + } + }); + } + }, + 'relationaloperator': { + label: 'Operator', + select: function(args) { + args.response.success({ + data: [ + { name: 'GT', description: 'greater-than' }, + { name: 'GE', description: 'greater-than or equals to' }, + { name: 'LT', description: 'less-than' }, + { name: 'LE', description: 'less-than or equals to' }, + { name: 'EQ', description: 'equals-to' } + ] + }); + } + }, + 'threshold': { edit: true, label: 'Threshold'}, + 'add-scaleDowncondition': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + scaleDownData.push($.extend(args.data, { + index: totalScaleDownCondition + })); + totalScaleDownCondition++; + args.response.success(); + } + }, + actions: { + destroy: { + label: '', + action: function(args) { + scaleDownData = $.grep(scaleDownData, function(item) { + return item.index != args.context.multiRule[0].index; + }); + totalScaleDownCondition--; + args.response.success(); + } + } + }, + dataProvider: function(args) { + var data = scaleDownData; + var $autoscaler = $('.ui-dialog .autoscaler'); + var initialData = $autoscaler.data('autoscaler-scale-down-data'); + + if ($.isArray(initialData)) { + $(initialData).each(function() { + this.index = totalScaleDownCondition; + totalScaleDownCondition++; + scaleDownData.push(this); + }); + + $autoscaler.data('autoscaler-scale-down-data', null); + } + + args.response.success({ + data: scaleDownData + }); + } + /* + actions: { + destroy: { + label: '', + action: function(args) { + $.ajax({ + url: createURL("deleteCondition&id=" + args.context.multiRule[0].counterid), + dataType: 'json', + async: true, + success: function(data) { + var jobId = data.deleteconditionresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + } + }); + } + }); + } + } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listConditions'), + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.map( + data.listconditionsresponse.condition ? + data.listconditionsresponse.condition : [], + function(elem) { + return { + counterid: elem.id, + relationaloperator: elem.relationaloperator, + threshold: elem.threshold + }; + } + ) + }); + } + }); + }*/ + } + }, + + actions: { + add: function(args) { + //validation (begin) ***** + if(isAdmin() || isDomainAdmin()) { //only admin and domain-admin has access to listUers API + var havingApiKeyAndSecretKey = false; + $.ajax({ + url: createURL('listUsers'), + data: { + id: args.data.username + }, + async: false, + success: function(json) { + if(json.listusersresponse.user[0].apikey != null && json.listusersresponse.user[0].secretkey != null) { + havingApiKeyAndSecretKey = true; + } + } + }); + if(havingApiKeyAndSecretKey == false) { + args.response.error('The selected user in advanced settings does not have API key or secret key'); + return; + } + } + + if(isAdmin()) { //only admin has access to listConfigurations API + var hasValidEndpointeUrl = false; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'endpointe.url' + }, + async: false, + success: function(json) { + if(json.listconfigurationsresponse.configuration != null) { + if(json.listconfigurationsresponse.configuration[0].value.indexOf('localhost') == -1) { + hasValidEndpointeUrl = true; + } + } + } + }); + if(hasValidEndpointeUrl == false) { + args.response.error("Global setting endpointe.url has to be set to the Management Server's API end point"); + return; + } + } + //validation (end) ***** + + + var scaleVmProfileResponse = []; + var loadBalancerResponse = []; + var scaleVmGroupResponse = []; + var scaleUpConditionIds = []; + var scaleDownConditionIds = []; + + var scaleUp = function(args){ + var scaleUpConditionIds = []; + $(scaleUpData).each(function(){ + var data = { + counterid: this.counterid, + relationaloperator: this.relationaloperator, + threshold: this.threshold + }; + $.ajax({ + url: createURL('createCondition'), + data: data, + success: function(json) { + var createConditionIntervalID = setInterval(function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobid=" + json.conditionresponse.jobid), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if(result.jobstatus == 0) { + return; + } + else { + clearInterval(createConditionIntervalID); + if(result.jobstatus == 1) { + var item = json.queryasyncjobresultresponse.jobresult.condition; + scaleUpConditionIds.push(item.id); + if (scaleUpConditionIds.length == scaleUpData.length) { + var data = { + action: 'scaleup', + conditionids: scaleUpConditionIds.join(","), + duration: args.data.scaleUpDuration, + quiettime: args.data.quietTime + }; + $.ajax({ + url: createURL('createAutoScalePolicy'), + data: data, + success: function(json) { + var jobId = json.autoscalepolicyresponse.jobid; + var createAutoScalePolicyInterval = setInterval(function(){ + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(createAutoScalePolicyInterval); + if (result.jobstatus == 1) { //AutoScalePolicy successfully created + var item = result.jobresult.autoscalepolicy; + scaleDown($.extend(args, { + scaleUpPolicyResponse: item + })); + } + else if (result.jobstatus == 2) { + args.response.error({ message: _s(result.jobresult.errortext) }); + } + } + } + }); + }, 3000); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + } + else if(result.jobstatus == 2) { + args.response.error({ message: _s(result.jobresult.errortext) }); + } + } + } + }); + }, 3000); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }); + }; + + var scaleDown = function(args){ + var scaleDownConditionIds = []; + $(scaleDownData).each(function(){ + var data = { + counterid: this.counterid, + relationaloperator: this.relationaloperator, + threshold: this.threshold + }; + $.ajax({ + url: createURL('createCondition'), + data: data, + success: function(json) { + var createConditionIntervalID = setInterval(function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobid=" + json.conditionresponse.jobid), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if(result.jobstatus == 0) { + return; + } + else { + clearInterval(createConditionIntervalID); + if(result.jobstatus == 1) { + var item = json.queryasyncjobresultresponse.jobresult.condition; + scaleDownConditionIds.push(item.id); + if (scaleDownConditionIds.length == scaleDownData.length) { + var data = { + action: 'scaledown', + conditionids: scaleDownConditionIds.join(","), + duration: args.data.scaleDownDuration, + quiettime: args.data.quietTime + }; + $.ajax({ + url: createURL('createAutoScalePolicy'), + data: data, + success: function(json) { + var jobId = json.autoscalepolicyresponse.jobid; + var createAutoScalePolicyInterval = setInterval(function(){ + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(createAutoScalePolicyInterval); + if (result.jobstatus == 1) { //AutoScalePolicy successfully created + var item = result.jobresult.autoscalepolicy; + createVmProfile($.extend(args, { + scaleDownPolicyResponse: item + })); + } + else if (result.jobstatus == 2) { + args.response.error({ message: _s(result.jobresult.errortext) }); + } + } + } + }); + }, 3000); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + } + else if(result.jobstatus == 2) { + args.response.error({ message: _s(result.jobresult.errortext) }); + } + } + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }, 3000); + } + }); + }); + }; + + var createVmProfile = function(args){ + var array1 = []; + array1.push("&zoneid=" + args.context.networks[0].zoneid); + array1.push("&templateid=" + args.data.templateNames); + array1.push("&serviceofferingid=" + args.data.serviceOfferingId); + array1.push("&snmpcommunity=" + args.data.snmpCommunity); + array1.push("&snmpport=" + args.data.snmpPort); + array1.push("&destroyvmgraceperiod=" + args.data.destroyVMgracePeriod); + + if(args.data.username != "") + array1.push("&autoscaleuserid=" + args.data.username); + + var array2 = []; + if(args.data.diskOfferingId != "") + array2.push("diskofferingid=" + args.data.diskOfferingId); + if(args.data.securityGroups != ""){ + if(array2.join("") != "") + array2.push("&securitygroupids=" + args.data.securityGroups); + else + array2.push("securitygroupids=" + args.data.securityGroups); + } + array2 = array2.join(""); + if(array2 != "") + array1.push("&otherdeployparams=" + encodeURIComponent(array2)); + + $.ajax({ + url: createURL('createAutoScaleVmProfile' + array1.join("")), + dataType: 'json', + async: true, + success: function(data) { + var jobId = data.autoscalevmprofileresponse.jobid; + var autoscaleVmProfileTimer = setInterval(function(){ + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(autoscaleVmProfileTimer); + if (result.jobstatus == 1) { //VM Profile successfully created + scaleVmProfileResponse = result.jobresult.autoscalevmprofile; + loadBalancer(args); + } + else if (result.jobstatus == 2) { + args.response.error({message: _s(result.jobresult.errortext)}); + } + } + } + }); + }, 3000); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }; + + var loadBalancer = function(args){ + var networkid; + if('vpc' in args.context) { //from VPC section + if(args.data.tier == null) { + cloudStack.dialog.notice({ message: 'Tier is required' }); + return; + } + networkid = args.data.tier; + } + else if('networks' in args.context) { //from Guest Network section + networkid = args.context.networks[0].id; + } + var data = { + algorithm: args.formData.algorithm, + name: args.formData.name, + privateport: args.formData.privateport, + publicport: args.formData.publicport, + openfirewall: false, + networkid: networkid, + publicipid: args.context.ipAddresses[0].id + }; + + $.ajax({ + url: createURL('createLoadBalancerRule'), + dataType: 'json', + data: data, + async: true, + success: function(json) { + var jobId = json.createloadbalancerruleresponse.jobid; + var loadBalancerTimer = setInterval(function(){ + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(loadBalancerTimer); + if (result.jobstatus == 1) { //LoadBalancerRule successfully created + loadBalancerResponse = result.jobresult.loadbalancer; + autoScaleVmGroup(args); + } + else if (result.jobstatus == 2) { + args.response.error({message: _s(result.jobresult.errortext)}); + } + } + } + }); + }, 3000); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }; + + var autoScaleVmGroup = function(args){ + var array1 = []; + array1.push("&lbruleid=" + loadBalancerResponse.id); + array1.push("&minMembers=" + args.data.minInstance); + array1.push("&maxMembers=" + args.data.maxInstance ); + array1.push("&vmprofileid=" + scaleVmProfileResponse.id); + array1.push("&interval=" + args.data.interval); + array1.push("&scaleuppolicyids=" + args.scaleUpPolicyResponse.id); + array1.push("&scaledownpolicyids=" + args.scaleDownPolicyResponse.id ); + $.ajax({ + url: createURL('createAutoScaleVmGroup' + array1.join("")), + dataType: 'json', + async: true, + success: function(json) { + var jobId = json.autoscalevmgroupresponse.jobid; + var scaleVmGroupTimer = setInterval(function(){ + $.ajax({ + url: createURL("queryAsyncJobResult&jobId="+jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } + else { + clearInterval(scaleVmGroupTimer); + if (result.jobstatus == 1) { //autoscale Vm group successfully created + scaleVmGroupResponse = result.jobresult.autoscalevmgroup; + args.response.success(); + } + else if (result.jobstatus == 2) { + args.response.error({message: _s(result.jobresult.errortext)}); + } + } + } + }); + }, 3000); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }; + + scaleUp(args); + + //setTimeout(function() { args.response.success(); }, 1000); + //setTimeout(function() { args.response.error('Error!'); }, 1000); + }, + destroy: function(args) { + $.ajax({ + url: createURL('') + }); + } + }, + + dialog: function(args) { + return function(args) { + var context = args.context; + + var $dialog= $('
'); + $dialog.dialog ({ + title: 'AutoScale Configuration Wizard', + closeonEscape: false, + + draggable:true, + width: 825 , + height :600, + buttons: { + 'Cancel': function() { + $(this).dialog("close"); + $('.overlay').remove(); + }, + + + 'Apply': function() { + $(':ui-dialog').remove(); + $('.overlay').remove(); + } + } + }).closest('.ui-dialog').overlay(); + + $("buttons").each(function() { + $(this).attr('style','float: right'); + }); + var $field = $('
').addClass('field username'); + var $input = $('').attr({ name: 'username' }); + var $inputLabel = $('