From c347c6bd095efa37387d5026124b85297a4dea07 Mon Sep 17 00:00:00 2001 From: Brian Federle Date: Thu, 28 Jun 2012 10:49:25 -0700 Subject: [PATCH] Add base VPC UI ** Note: this is a work-in-progress, and only contains dummy content Implement UI for managing VPC tiers, via a custom chart-like UI list tiers and allowing the management of VMs associated with the VPCs. --- ui/css/cloudstack3.css | 352 ++++++++++++++++- ui/images/bg-gradients.png | Bin 8322 -> 7539 bytes ui/index.jsp | 3 + ui/scripts/instanceWizard.js | 513 +++++++++++++++++++++++++ ui/scripts/instances.js | 513 +------------------------ ui/scripts/network.js | 87 ++++- ui/scripts/ui-custom/instanceWizard.js | 2 +- ui/scripts/ui-custom/vpc.js | 404 +++++++++++++++++++ ui/scripts/vpc.js | 469 ++++++++++++++++++++++ 9 files changed, 1825 insertions(+), 518 deletions(-) create mode 100644 ui/scripts/instanceWizard.js create mode 100644 ui/scripts/ui-custom/vpc.js create mode 100644 ui/scripts/vpc.js diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 573afe9daf9..7fbc3668733 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -8837,6 +8837,346 @@ div.panel.ui-dialog div.list-view div.fixed-header { background: #DFE1E3; } +/*VPC / vApps*/ +.vpc-chart { + width: 100%; + height: 93%; + overflow: auto; + position: relative; + margin: 30px 0 0; +} + +.vpc-chart .vpc-title { + font-size: 24px; + /*+placement:shift 50px 40px;*/ + position: relative; + left: 50px; + top: 40px; + position: absolute; + color: #5F768A; +} + +.vpc-chart ul.tiers { + padding: 0 0 0 26px; + margin: 79px 0 0 232px; + border-left: 3px solid #CCC; +} + +.vpc-chart li.tier { + display: block; + width: 258px; + height: 107px; + margin: -55px 0 90px; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + border: 1px solid #50545A; + background: url(../images/bg-gradients.png) 0px -2637px; + /*+placement:shift 0px 58px;*/ + position: relative; + left: 0px; + top: 58px; + position: relative; + /*+box-shadow:0px 5px 7px #DADADA;*/ + -moz-box-shadow: 0px 5px 7px #DADADA; + -webkit-box-shadow: 0px 5px 7px #DADADA; + -o-box-shadow: 0px 5px 7px #DADADA; + box-shadow: 0px 5px 7px #DADADA; +} + +.vpc-chart li.tier .loading-overlay { + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; +} + +.vpc-chart li.tier .connect-line { + position: absolute; + width: 28px; + height: 3px; + background: #CCCCCC 0px -8px; + /*+placement:shift -29px 49px;*/ + position: relative; + left: -29px; + top: 49px; + position: absolute; +} + +.vpc-chart li.tier span.title { + color: #FFFFFF; + /*+placement:shift 11px 13px;*/ + position: relative; + left: 11px; + top: 13px; + position: absolute; + font-size: 24px; + /*+text-shadow:1px 2px 2px #000000;*/ + -moz-text-shadow: 1px 2px 2px #000000; + -webkit-text-shadow: 1px 2px 2px #000000; + -o-text-shadow: 1px 2px 2px #000000; + text-shadow: 1px 2px 2px #000000; +} + +.vpc-chart li.tier span.cidr { + /*+placement:shift 12px 46px;*/ + position: relative; + left: 12px; + top: 46px; + position: absolute; + font-size: 14px; + /*+text-shadow:0px -1px 1px #343E4C;*/ + -moz-text-shadow: 0px -1px 1px #343E4C; + -webkit-text-shadow: 0px -1px 1px #343E4C; + -o-text-shadow: 0px -1px 1px #343E4C; + text-shadow: 0px -1px 1px #343E4C; + color: #FFFFFF; +} + +.vpc-chart li.tier .actions { + width: 258px; + height: 35px; + background: #CCC; + /*+border-radius:0 0 4px 4px;*/ + -moz-border-radius: 0 0 4px 4px; + -webkit-border-radius: 0 0 4px 4px; + -khtml-border-radius: 0 0 4px 4px; + border-radius: 0 0 4px 4px; + /*+placement:shift -1px 71px;*/ + position: relative; + left: -1px; + top: 71px; + position: absolute; + /*+box-shadow:inset 0px 1px #FFFFFF;*/ + -moz-box-shadow: inset 0px 1px #FFFFFF; + -webkit-box-shadow: inset 0px 1px #FFFFFF; + -o-box-shadow: inset 0px 1px #FFFFFF; + box-shadow: inset 0px 1px #FFFFFF; + border: 1px solid #808080; + border-top: 1px solid #4C545E; + position: absolute; +} + +.vpc-chart li.tier .actions .action { + cursor: pointer; + float: left; + width: 50px; + height: 24px; + text-align: center; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + margin: 4px 0px 4px 4px; + border: 1px solid #909090; + color: #4B637A; + font-weight: bold; + /*+text-shadow:0px 1px 1px #FFFFFF;*/ + -moz-text-shadow: 0px 1px 1px #FFFFFF; + -webkit-text-shadow: 0px 1px 1px #FFFFFF; + -o-text-shadow: 0px 1px 1px #FFFFFF; + text-shadow: 0px 1px 1px #FFFFFF; + background: url(../images/bg-gradients.png) 0px -2533px; +} + +.vpc-chart li.tier .actions .action.disabled, +.vpc-chart li.tier .actions .action.disabled:hover { + color: #9D9D9D; + background: #CFCFCF; + /*+text-shadow:none;*/ + -moz-text-shadow: none; + -webkit-text-shadow: none; + -o-text-shadow: none; + text-shadow: none; + border-color: #B5B5B5; + cursor: not-allowed; + /*+box-shadow:none;*/ + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; + box-shadow: none; +} + +.vpc-chart li.tier .actions .action:hover { + border: 1px solid #7A8B9A; + background-position: 0px -106px; + color: #5B7A96; + /*+box-shadow:inset 1px 2px 4px #808080;*/ + -moz-box-shadow: inset 1px 2px 4px #808080; + -webkit-box-shadow: inset 1px 2px 4px #808080; + -o-box-shadow: inset 1px 2px 4px #808080; + box-shadow: inset 1px 2px 4px #808080; +} + +.vpc-chart li.tier .actions .action span.label { + /*+placement:shift 1px 3px;*/ + position: relative; + left: 1px; + top: 3px; + font-size: 11px; +} + +.vpc-chart li.tier .actions .action.remove, +.vpc-chart li.tier .actions .action.remove:hover { + background: none; + width: 30px; + padding: 0; + float: right; + border: none; + /*+placement:shift -3px -2px;*/ + position: relative; + left: -3px; + top: -2px; + /*+box-shadow:none;*/ + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; + box-shadow: none; +} + +.vpc-chart li.tier .action span.icon { + background-image: url(../images/sprites.png); + cursor: pointer; + width: 37px; + height: 23px; + float: left; + /*+placement:shift 1px 3px;*/ + position: relative; + left: 1px; + top: 3px; +} + +.vpc-chart li.tier .vm-count { + font-size: 23px; + left: 134px; + top: 3px; + position: absolute; + color: #FFFFFF; + /*+text-shadow:1px 2px 2px #000000;*/ + -moz-text-shadow: 1px 2px 2px #000000; + -webkit-text-shadow: 1px 2px 2px #000000; + -o-text-shadow: 1px 2px 2px #000000; + text-shadow: 1px 2px 2px #000000; + cursor: pointer; + display: block; + padding: 5px; + text-align: center; + width: 100px; + border: 1px solid transparent; + margin: 4px; +} + +.vpc-chart li.tier .vm-count:hover { + border-radius: 4px; + border: 1px solid #4C545E; + background: url(../images/bg-gradients.png) 0px -2751px; +} + +.vpc-chart li.tier .vm-count .total { + padding-right: 4px; + font-size: 24px; +} + +.vpc-chart li.tier.placeholder { + background: #ECECEC; + border: dotted #ACACAC; + /*+border-radius:4px;*/ + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + -khtml-border-radius: 4px; + border-radius: 4px; + /*+box-shadow:none;*/ + -moz-box-shadow: none; + -webkit-box-shadow: none; + -o-box-shadow: none; + box-shadow: none; + cursor: pointer; +} + +.vpc-chart li.tier.placeholder:hover { + background: #D3D3D3; + /*+box-shadow:0px 2px 8px #A7A7A7;*/ + -moz-box-shadow: 0px 2px 8px #A7A7A7; + -webkit-box-shadow: 0px 2px 8px #A7A7A7; + -o-box-shadow: 0px 2px 8px #A7A7A7; + box-shadow: 0px 2px 8px #A7A7A7; +} + +.vpc-chart li.tier.placeholder span { + top: 40px; + left: 66px; + color: #9F9F9F; + /*+text-shadow:none;*/ + -moz-text-shadow: none; + -webkit-text-shadow: none; + -o-text-shadow: none; + text-shadow: none; +} + +.vpc-chart li.tier.placeholder:hover span { + color: #000000; + /*+text-shadow:0px 0px 7px #FFFFFF;*/ + -moz-text-shadow: 0px 0px 7px #FFFFFF; + -webkit-text-shadow: 0px 0px 7px #FFFFFF; + -o-text-shadow: 0px 0px 7px #FFFFFF; + text-shadow: 0px 0px 7px #FFFFFF; +} + +.vpc-chart li.tier.virtual-router { + margin: 0px; + width: 222px; + height: 65px; + /*+placement:shift 17px -36px;*/ + position: relative; + left: 17px; + top: -36px; + background-position: 0px -2519px; + border: 1px solid #ADADAD; +} + +.vpc-chart li.tier.virtual-router span { + color: #586E82; + font-size: 18px; + /*+text-shadow:0px 1px 3px #FFFFFF;*/ + -moz-text-shadow: 0px 1px 3px #FFFFFF; + -webkit-text-shadow: 0px 1px 3px #FFFFFF; + -o-text-shadow: 0px 1px 3px #FFFFFF; + text-shadow: 0px 1px 3px #FFFFFF; + /*+placement:shift 53px 22px;*/ + position: relative; + left: 53px; + top: 22px; +} + +.vpc-chart li.tier.virtual-router .connect-line { + /*+placement:shift -47px 14px;*/ + position: relative; + left: -47px; + top: 14px; + width: 46px; +} + +/*Configure ACL dialog*/ +.ui-dialog.configure-acl { +} + +.ui-dialog.configure-acl .ui-dialog-buttonpane { + /*+placement:shift 709px -2px;*/ + position: relative; + left: 709px; + top: -2px; +} + +.ui-dialog.configure-acl .multi-edit .data { + width: 807px; + height: 370px; + overflow: auto; +} + /*Action icons*/ .action.edit .icon { background-position: 1px -1px; @@ -9005,13 +9345,15 @@ div.panel.ui-dialog div.list-view div.fixed-header { .create .icon, .createTemplate .icon, -.enableSwift .icon { +.enableSwift .icon, +.addVM .icon { background-position: -69px -63px; } .create:hover .icon, .createTemplate:hover .icon, -.enableSwift:hover .icon { +.enableSwift:hover .icon, +.addVM:hover .icon { background-position: -69px -645px; } @@ -9073,11 +9415,13 @@ div.panel.ui-dialog div.list-view div.fixed-header { background-position: -167px -648px; } -.generateKeys .icon { +.generateKeys .icon, +.networkACL .icon { background-position: -167px -95px; } -.generateKeys:hover .icon { +.generateKeys:hover .icon, +.networkACL:hover .icon { background-position: -167px -677px; } diff --git a/ui/images/bg-gradients.png b/ui/images/bg-gradients.png index 2ef74540bbf8aa6c7001afa9575456b65552db1f..52016f0cf487158c238037ef50e51ae64d124d9a 100644 GIT binary patch literal 7539 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 literal 8322 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 bRY?5C&d + + + diff --git a/ui/scripts/instanceWizard.js b/ui/scripts/instanceWizard.js new file mode 100644 index 00000000000..8559477573d --- /dev/null +++ b/ui/scripts/instanceWizard.js @@ -0,0 +1,513 @@ +(function($, cloudStack) { + var zoneObjs, hypervisorObjs, featuredTemplateObjs, communityTemplateObjs, myTemplateObjs, featuredIsoObjs, community + var selectedZoneObj, selectedTemplateObj, selectedHypervisor, selectedDiskOfferingObj; + var step5ContainerType = 'nothing-to-select'; //'nothing-to-select', 'select-network', 'select-security-group' + + cloudStack.instanceWizard = { + maxDiskOfferingSize: function() { + return g_capabilities.customdiskofferingmaxsize; + }, + steps: [ + // Step 1: Setup + function(args) { + $.ajax({ + url: createURL("listZones&available=true"), + dataType: "json", + async: false, + success: function(json) { + zoneObjs = json.listzonesresponse.zone; + args.response.success({ data: {zones: zoneObjs}}); + } + }); + }, + + // Step 2: Select template + function(args) { + $(zoneObjs).each(function(){ + if(this.id == args.currentData.zoneid) { + selectedZoneObj = this; + return false; //break the $.each() loop + } + }); + if(selectedZoneObj == null) { + alert("error: can't find matched zone object"); + return; + } + + $.ajax({ + url: createURL("listHypervisors&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + hypervisorObjs = json.listhypervisorsresponse.hypervisor; + } + }); + + //***** get templates/ISOs (begin) ***** + var selectedTemplate = args.currentData['select-template']; + if (selectedTemplate == 'select-template') { + var hypervisorArray = []; + $(hypervisorObjs).each(function(index, item) { + hypervisorArray.push(item.name); + }); + + $.ajax({ + url: createURL("listTemplates&templatefilter=featured&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + featuredTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { + if($.inArray(item.hypervisor, hypervisorArray) > -1) + return true; + }); + } + }); + $.ajax({ + url: createURL("listTemplates&templatefilter=community&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + communityTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { + if($.inArray(item.hypervisor, hypervisorArray) > -1) + return true; + }); + } + }); + $.ajax({ + url: createURL("listTemplates&templatefilter=selfexecutable&zoneid="+args.currentData.zoneid), + dataType: "json", + async: false, + success: function(json) { + myTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { + if($.inArray(item.hypervisor, hypervisorArray) > -1) + return true; + }); + } + }); + } else if (selectedTemplate == 'select-iso') { + $.ajax({ + url: createURL("listIsos&isofilter=featured&zoneid=" + args.currentData.zoneid + "&bootable=true"), + dataType: "json", + async: false, + success: function(json) { + featuredIsoObjs = json.listisosresponse.iso; + } + }); + $.ajax({ + url: createURL("listIsos&isofilter=community&zoneid=" + args.currentData.zoneid + "&bootable=true"), + dataType: "json", + async: false, + success: function(json) { + communityIsoObjs = json.listisosresponse.iso; + } + }); + $.ajax({ + url: createURL("listIsos&isofilter=selfexecutable&zoneid=" + args.currentData.zoneid + "&bootable=true"), + dataType: "json", + async: false, + success: function(json) { + myIsoObjs = json.listisosresponse.iso; + } + }); + } + //***** get templates/ISOs (end) ***** + + + var templatesObj = {}; + if (selectedTemplate == 'select-template') { + templatesObj = { + featuredtemplates: featuredTemplateObjs, + communitytemplates: communityTemplateObjs, + mytemplates: myTemplateObjs + } + } else if (selectedTemplate == 'select-iso') { + templatesObj = { + featuredisos: featuredIsoObjs, + communityisos: communityIsoObjs, + myisos: myIsoObjs + } + } + args.response.success({ + hypervisor: { + idField: 'name', + nameField: 'name' + }, + data: { + templates: templatesObj, + hypervisors: hypervisorObjs + } + }); + }, + + // Step 3: Service offering + function(args) { + if(args.currentData["select-template"] == "select-template") { + if(featuredTemplateObjs != null && featuredTemplateObjs.length > 0) { + for(var i=0; i < featuredTemplateObjs.length; i++) { + if(featuredTemplateObjs[i].id == args.currentData.templateid) { + selectedTemplateObj = featuredTemplateObjs[i]; + break; + } + } + } + if(selectedTemplateObj == null) { + if(communityTemplateObjs != null && communityTemplateObjs.length > 0) { + for(var i=0; i < communityTemplateObjs.length; i++) { + if(communityTemplateObjs[i].id == args.currentData.templateid) { + selectedTemplateObj = communityTemplateObjs[i]; + break; + } + } + } + } + if(selectedTemplateObj == null) { + if(myTemplateObjs != null && myTemplateObjs.length > 0) { + for(var i=0; i < myTemplateObjs.length; i++) { + if(myTemplateObjs[i].id == args.currentData.templateid) { + selectedTemplateObj = myTemplateObjs[i]; + break; + } + } + } + } + if(selectedTemplateObj == null) + alert("unable to find matched template object"); + else + selectedHypervisor = selectedTemplateObj.hypervisor; + } + else { //(args.currentData["select-template"] == "select-iso" + selectedHypervisor = args.currentData.hypervisorid; + } + + $.ajax({ + url: createURL("listServiceOfferings&issystem=false"), + dataType: "json", + async: true, + success: function(json) { + serviceOfferingObjs = json.listserviceofferingsresponse.serviceoffering; + args.response.success({ + data: {serviceOfferings: serviceOfferingObjs} + }); + } + }); + }, + + // Step 4: Data disk offering + function(args) { + var isRequred = (args.currentData["select-template"] == "select-iso"? true: false); + $.ajax({ + url: createURL("listDiskOfferings"), + dataType: "json", + async: true, + success: function(json) { + diskOfferingObjs = json.listdiskofferingsresponse.diskoffering; + args.response.success({ + required: isRequred, + customFlag: 'iscustomized', // Field determines if custom slider is shown + data: {diskOfferings: diskOfferingObjs} + }); + } + }); + }, + + // Step 5: Network + function(args) { + if(diskOfferingObjs != null && diskOfferingObjs.length > 0) { + for(var i=0; i < diskOfferingObjs.length; i++) { + if(diskOfferingObjs[i].id == args.currentData.diskofferingid) { + selectedDiskOfferingObj = diskOfferingObjs[i]; + break; + } + } + } + + if (selectedZoneObj.networktype == "Advanced") { //Advanced zone. Show network list. + step5ContainerType = 'select-network'; + } + else { //Basic zone. Show securigy group list or nothing(when no SecurityGroup service in guest network) + var includingSecurityGroupService = false; + $.ajax({ + url: createURL("listNetworks&trafficType=Guest&zoneId=" + selectedZoneObj.id), + dataType: "json", + async: false, + success: function(json) { + //basic zone should have only one guest network returned in this API call + var items = json.listnetworksresponse.network; + if(items != null && items.length > 0) { + var networkObj = items[0]; //basic zone has only one guest network + var serviceObjArray = networkObj.service; + for(var k = 0; k < serviceObjArray.length; k++) { + if(serviceObjArray[k].name == "SecurityGroup") { + includingSecurityGroupService = true; + break; + } + } + } + } + }); + + if(includingSecurityGroupService == false || selectedHypervisor == "VMware") { + step5ContainerType = 'nothing-to-select'; + } + else { + step5ContainerType = 'select-security-group'; + } + } + + //step5ContainerType = 'nothing-to-select'; //for testing only, comment it out before checking in + if(step5ContainerType == 'select-network') { + var defaultNetworkArray = [], optionalNetworkArray = []; + var networkData = { + zoneId: args.currentData.zoneid + }; + + if (!(cloudStack.context.projects && cloudStack.context.projects[0])) { + networkData.domainid = g_domainid; + networkData.account = g_account; + } + + var networkObjs; + $.ajax({ + url: createURL('listNetworks'), + data: networkData, + dataType: "json", + async: false, + success: function(json) { + networkObjs = json.listnetworksresponse.network ? json.listnetworksresponse.network : []; + } + }); + + + var apiCmd = "listNetworkOfferings&guestiptype=Isolated&supportedServices=sourceNat&state=Enabled&specifyvlan=false&zoneid=" + args.currentData.zoneid ; + var array1 = []; + var guestTrafficTypeTotal = 0; + + $.ajax({ + url: createURL(apiCmd + array1.join("")), //get the network offering for isolated network with sourceNat + dataType: "json", + async: false, + success: function(json) { + networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; + } + }); + //get network offerings (end) *** + + + args.response.success({ + type: 'select-network', + data: { + myNetworks: [], //not used any more + sharedNetworks: networkObjs, + securityGroups: [], + networkOfferings: networkOfferingObjs + } + }); + } + + else if(step5ContainerType == 'select-security-group') { + var securityGroupArray = []; + var data = { + domainid: g_domainid, + account: g_account + }; + + $.ajax({ + url: createURL("listSecurityGroups"), + dataType: "json", + async: false, + data: cloudStack.context.projects ? {} : data, + success: function(json) { + var items = json.listsecuritygroupsresponse.securitygroup; + if (items != null && items.length > 0) { + for (var i = 0; i < items.length; i++) { + if(items[i].name != "default") //exclude default security group because it is always applied + securityGroupArray.push(items[i]); + } + } + } + }); + args.response.success({ + type: 'select-security-group', + data: { + myNetworks: [], //not used any more + sharedNetworks: [], + securityGroups: securityGroupArray, + networkOfferings: [] + } + }); + } + + else if(step5ContainerType == 'nothing-to-select') { + args.response.success({ + type: 'nothing-to-select', + data: { + myNetworks: [], //not used any more + sharedNetworks: [], + securityGroups: [], + networkOfferings: [] + } + }); + } + + }, + + // Step 6: Review + function(args) { + return false; + } + ], + action: function(args) { +/* +var isValid = true; +isValid &= validateString("Name", $thisPopup.find("#wizard_vm_name"), $thisPopup.find("#wizard_vm_name_errormsg"), true); //optional +isValid &= validateString("Group", $thisPopup.find("#wizard_vm_group"), $thisPopup.find("#wizard_vm_group_errormsg"), true); //optional +if (!isValid) +return; +*/ + + // Create a new VM!!!! + var array1 = []; + + //step 1 : select zone + array1.push("&zoneId=" + args.data.zoneid); + + //step 2: select template + array1.push("&templateId=" + args.data.templateid); + array1.push("&hypervisor=" + selectedHypervisor); + + //step 3: select service offering + array1.push("&serviceOfferingId=" + args.data.serviceofferingid); + + //step 4: select disk offering + if(args.data.diskofferingid != null && args.data.diskofferingid != "0") { + array1.push("&diskOfferingId=" + args.data.diskofferingid); + if(selectedDiskOfferingObj.iscustomized == true) + array1.push("&size=" + args.data.size); + } + + //step 5: select network + if (step5ContainerType == 'select-network') { + var array2 = []; + var defaultNetworkId = args.data.defaultNetwork; //args.data.defaultNetwork might be equal to string "new-network" or a network ID + + var checkedNetworkIdArray; + if(typeof(args.data["my-networks"]) == "object" && args.data["my-networks"].length != null) { //args.data["my-networks"] is an array of string, e.g. ["203", "202"], + checkedNetworkIdArray = args.data["my-networks"]; + } + else if(typeof(args.data["my-networks"]) == "string" && args.data["my-networks"].length > 0) { //args.data["my-networks"] is a string, e.g. "202" + checkedNetworkIdArray = []; + checkedNetworkIdArray.push(args.data["my-networks"]); + } + else { // typeof(args.data["my-networks"]) == null + checkedNetworkIdArray = []; + } + + //create new network starts here + if(args.data["new-network"] == "create-new-network") { + var isCreateNetworkSuccessful = true; + $.ajax({ + url: createURL("createNetwork&networkOfferingId="+args.data["new-network-networkofferingid"]+"&name="+todb(args.data["new-network-name"])+"&displayText="+todb(args.data["new-network-name"])+"&zoneId="+selectedZoneObj.id), + dataType: "json", + async: false, + success: function(json) { + newNetwork = json.createnetworkresponse.network; + checkedNetworkIdArray.push(newNetwork.id); + if(defaultNetworkId == "new-network") + defaultNetworkId = newNetwork.id; + }, + error: function(XMLHttpResponse) { + isCreateNetworkSuccessful = false; + var errorMsg = "Failed to create new network, unable to proceed to deploy VM. Error: " + parseXMLHttpResponse(XMLHttpResponse); + //alert(errorMsg); + args.response.error(errorMsg); //args.response.error(errorMsg) here doesn't show errorMsg. Waiting for Brian to fix it. use alert(errorMsg) to show errorMsg for now. + } + }); + if(isCreateNetworkSuccessful == false) + return; + } + //create new network ends here + + //add default network first + if(defaultNetworkId != null && defaultNetworkId.length > 0) + array2.push(defaultNetworkId); + + //then, add other checked networks + if(checkedNetworkIdArray.length > 0) { + for(var i=0; i < checkedNetworkIdArray.length; i++) { + if(checkedNetworkIdArray[i] != defaultNetworkId) //exclude defaultNetworkId that has been added to array2 + array2.push(checkedNetworkIdArray[i]); + } + } + + array1.push("&networkIds=" + array2.join(",")); + } + else if (step5ContainerType == 'select-security-group') { + var checkedSecurityGroupIdArray; + if(typeof(args.data["security-groups"]) == "object" && args.data["security-groups"].length != null) { //args.data["security-groups"] is an array of string, e.g. ["2375f8cc-8a73-4b8d-9b26-50885a25ffe0", "27c60d2a-de7f-4bb7-96e5-a602cec681df","c6301d77-99b5-4e8a-85e2-3ea2ab31c342"], + checkedSecurityGroupIdArray = args.data["security-groups"]; + } + else if(typeof(args.data["security-groups"]) == "string" && args.data["security-groups"].length > 0) { //args.data["security-groups"] is a string, e.g. "2375f8cc-8a73-4b8d-9b26-50885a25ffe0" + checkedSecurityGroupIdArray = []; + checkedSecurityGroupIdArray.push(args.data["security-groups"]); + } + else { // typeof(args.data["security-groups"]) == null + checkedSecurityGroupIdArray = []; + } + + if(checkedSecurityGroupIdArray.length > 0) + array1.push("&securitygroupids=" + checkedSecurityGroupIdArray.join(",")); + } + + var displayname = args.data.displayname; + if(displayname != null && displayname.length > 0) { + array1.push("&displayname="+todb(displayname)); + array1.push("&name="+todb(displayname)); + } + + var group = args.data.groupname; + if (group != null && group.length > 0) + array1.push("&group="+todb(group)); + + //array1.push("&startVm=false"); //for testing only, comment it out before checking in + + $.ajax({ + url: createURL("deployVirtualMachine"+array1.join("")), + dataType: "json", + success: function(json) { + var jid = json.deployvirtualmachineresponse.jobid; + var vmid = json.deployvirtualmachineresponse.id; + args.response.success( + {_custom: + {jobId: jid, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.virtualmachine; + if (item.password != null) + alert("Password of new VM " + item.displayname + " is " + item.password); + return item; + }, + getActionFilter: function() { + return vmActionfilter; + }, + getUpdatedItemWhenAsyncJobFails: function() { + var item; + $.ajax({ + url: createURL("listVirtualMachines&id="+vmid), + dataType: "json", + async: false, + success: function(json) { + item = json.listvirtualmachinesresponse.virtualmachine[0]; + } + }); + return item; + } + } + } + ); + }, + error: function(XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); //wait for Brian to implement + } + }); + } + }; +}(jQuery, cloudStack)); diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index 77688c978a6..5e9b3f3bb32 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -15,11 +15,6 @@ // specific language governing permissions and limitations // under the License. (function($, cloudStack) { - - var zoneObjs, hypervisorObjs, featuredTemplateObjs, communityTemplateObjs, myTemplateObjs, featuredIsoObjs, communityIsoObjs, myIsoObjs, serviceOfferingObjs, diskOfferingObjs, networkOfferingObjs, physicalNetworkObjs; - var selectedZoneObj, selectedTemplateObj, selectedHypervisor, selectedDiskOfferingObj; - var step5ContainerType = 'nothing-to-select'; //'nothing-to-select', 'select-network', 'select-security-group' - cloudStack.sections.instances = { title: 'label.instances', id: 'instances', @@ -69,513 +64,7 @@ label: 'label.vm.add', action: { - custom: cloudStack.instanceWizard({ - maxDiskOfferingSize: function() { - return g_capabilities.customdiskofferingmaxsize; - }, - steps: [ - // Step 1: Setup - function(args) { - $.ajax({ - url: createURL("listZones&available=true"), - dataType: "json", - async: false, - success: function(json) { - zoneObjs = json.listzonesresponse.zone; - args.response.success({ data: {zones: zoneObjs}}); - } - }); - }, - - // Step 2: Select template - function(args) { - $(zoneObjs).each(function(){ - if(this.id == args.currentData.zoneid) { - selectedZoneObj = this; - return false; //break the $.each() loop - } - }); - if(selectedZoneObj == null) { - alert("error: can't find matched zone object"); - return; - } - - $.ajax({ - url: createURL("listHypervisors&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - hypervisorObjs = json.listhypervisorsresponse.hypervisor; - } - }); - - //***** get templates/ISOs (begin) ***** - var selectedTemplate = args.currentData['select-template']; - if (selectedTemplate == 'select-template') { - var hypervisorArray = []; - $(hypervisorObjs).each(function(index, item) { - hypervisorArray.push(item.name); - }); - - $.ajax({ - url: createURL("listTemplates&templatefilter=featured&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - featuredTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { - if($.inArray(item.hypervisor, hypervisorArray) > -1) - return true; - }); - } - }); - $.ajax({ - url: createURL("listTemplates&templatefilter=community&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - communityTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { - if($.inArray(item.hypervisor, hypervisorArray) > -1) - return true; - }); - } - }); - $.ajax({ - url: createURL("listTemplates&templatefilter=selfexecutable&zoneid="+args.currentData.zoneid), - dataType: "json", - async: false, - success: function(json) { - myTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) { - if($.inArray(item.hypervisor, hypervisorArray) > -1) - return true; - }); - } - }); - } else if (selectedTemplate == 'select-iso') { - $.ajax({ - url: createURL("listIsos&isofilter=featured&zoneid=" + args.currentData.zoneid + "&bootable=true"), - dataType: "json", - async: false, - success: function(json) { - featuredIsoObjs = json.listisosresponse.iso; - } - }); - $.ajax({ - url: createURL("listIsos&isofilter=community&zoneid=" + args.currentData.zoneid + "&bootable=true"), - dataType: "json", - async: false, - success: function(json) { - communityIsoObjs = json.listisosresponse.iso; - } - }); - $.ajax({ - url: createURL("listIsos&isofilter=selfexecutable&zoneid=" + args.currentData.zoneid + "&bootable=true"), - dataType: "json", - async: false, - success: function(json) { - myIsoObjs = json.listisosresponse.iso; - } - }); - } - //***** get templates/ISOs (end) ***** - - - var templatesObj = {}; - if (selectedTemplate == 'select-template') { - templatesObj = { - featuredtemplates: featuredTemplateObjs, - communitytemplates: communityTemplateObjs, - mytemplates: myTemplateObjs - } - } else if (selectedTemplate == 'select-iso') { - templatesObj = { - featuredisos: featuredIsoObjs, - communityisos: communityIsoObjs, - myisos: myIsoObjs - } - } - args.response.success({ - hypervisor: { - idField: 'name', - nameField: 'name' - }, - data: { - templates: templatesObj, - hypervisors: hypervisorObjs - } - }); - }, - - // Step 3: Service offering - function(args) { - if(args.currentData["select-template"] == "select-template") { - if(featuredTemplateObjs != null && featuredTemplateObjs.length > 0) { - for(var i=0; i < featuredTemplateObjs.length; i++) { - if(featuredTemplateObjs[i].id == args.currentData.templateid) { - selectedTemplateObj = featuredTemplateObjs[i]; - break; - } - } - } - if(selectedTemplateObj == null) { - if(communityTemplateObjs != null && communityTemplateObjs.length > 0) { - for(var i=0; i < communityTemplateObjs.length; i++) { - if(communityTemplateObjs[i].id == args.currentData.templateid) { - selectedTemplateObj = communityTemplateObjs[i]; - break; - } - } - } - } - if(selectedTemplateObj == null) { - if(myTemplateObjs != null && myTemplateObjs.length > 0) { - for(var i=0; i < myTemplateObjs.length; i++) { - if(myTemplateObjs[i].id == args.currentData.templateid) { - selectedTemplateObj = myTemplateObjs[i]; - break; - } - } - } - } - if(selectedTemplateObj == null) - alert("unable to find matched template object"); - else - selectedHypervisor = selectedTemplateObj.hypervisor; - } - else { //(args.currentData["select-template"] == "select-iso" - selectedHypervisor = args.currentData.hypervisorid; - } - - $.ajax({ - url: createURL("listServiceOfferings&issystem=false"), - dataType: "json", - async: true, - success: function(json) { - serviceOfferingObjs = json.listserviceofferingsresponse.serviceoffering; - args.response.success({ - data: {serviceOfferings: serviceOfferingObjs} - }); - } - }); - }, - - // Step 4: Data disk offering - function(args) { - var isRequred = (args.currentData["select-template"] == "select-iso"? true: false); - $.ajax({ - url: createURL("listDiskOfferings"), - dataType: "json", - async: true, - success: function(json) { - diskOfferingObjs = json.listdiskofferingsresponse.diskoffering; - args.response.success({ - required: isRequred, - customFlag: 'iscustomized', // Field determines if custom slider is shown - data: {diskOfferings: diskOfferingObjs} - }); - } - }); - }, - - // Step 5: Network - function(args) { - if(diskOfferingObjs != null && diskOfferingObjs.length > 0) { - for(var i=0; i < diskOfferingObjs.length; i++) { - if(diskOfferingObjs[i].id == args.currentData.diskofferingid) { - selectedDiskOfferingObj = diskOfferingObjs[i]; - break; - } - } - } - - if (selectedZoneObj.networktype == "Advanced") { //Advanced zone. Show network list. - step5ContainerType = 'select-network'; - } - else { //Basic zone. Show securigy group list or nothing(when no SecurityGroup service in guest network) - var includingSecurityGroupService = false; - $.ajax({ - url: createURL("listNetworks&trafficType=Guest&zoneId=" + selectedZoneObj.id), - dataType: "json", - async: false, - success: function(json) { - //basic zone should have only one guest network returned in this API call - var items = json.listnetworksresponse.network; - if(items != null && items.length > 0) { - var networkObj = items[0]; //basic zone has only one guest network - var serviceObjArray = networkObj.service; - for(var k = 0; k < serviceObjArray.length; k++) { - if(serviceObjArray[k].name == "SecurityGroup") { - includingSecurityGroupService = true; - break; - } - } - } - } - }); - - if(includingSecurityGroupService == false || selectedHypervisor == "VMware") { - step5ContainerType = 'nothing-to-select'; - } - else { - step5ContainerType = 'select-security-group'; - } - } - - //step5ContainerType = 'nothing-to-select'; //for testing only, comment it out before checking in - if(step5ContainerType == 'select-network') { - var defaultNetworkArray = [], optionalNetworkArray = []; - var networkData = { - zoneId: args.currentData.zoneid - }; - - if (!(cloudStack.context.projects && cloudStack.context.projects[0])) { - networkData.domainid = g_domainid; - networkData.account = g_account; - } - - var networkObjs; - $.ajax({ - url: createURL('listNetworks'), - data: networkData, - dataType: "json", - async: false, - success: function(json) { - networkObjs = json.listnetworksresponse.network ? json.listnetworksresponse.network : []; - } - }); - - - var apiCmd = "listNetworkOfferings&guestiptype=Isolated&supportedServices=sourceNat&state=Enabled&specifyvlan=false&zoneid=" + args.currentData.zoneid ; - var array1 = []; - var guestTrafficTypeTotal = 0; - - $.ajax({ - url: createURL(apiCmd + array1.join("")), //get the network offering for isolated network with sourceNat - dataType: "json", - async: false, - success: function(json) { - networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; - } - }); - //get network offerings (end) *** - - - args.response.success({ - type: 'select-network', - data: { - myNetworks: [], //not used any more - sharedNetworks: networkObjs, - securityGroups: [], - networkOfferings: networkOfferingObjs - } - }); - } - - else if(step5ContainerType == 'select-security-group') { - var securityGroupArray = []; - var data = { - domainid: g_domainid, - account: g_account - }; - - $.ajax({ - url: createURL("listSecurityGroups"), - dataType: "json", - async: false, - data: cloudStack.context.projects ? {} : data, - success: function(json) { - var items = json.listsecuritygroupsresponse.securitygroup; - if (items != null && items.length > 0) { - for (var i = 0; i < items.length; i++) { - if(items[i].name != "default") //exclude default security group because it is always applied - securityGroupArray.push(items[i]); - } - } - } - }); - args.response.success({ - type: 'select-security-group', - data: { - myNetworks: [], //not used any more - sharedNetworks: [], - securityGroups: securityGroupArray, - networkOfferings: [] - } - }); - } - - else if(step5ContainerType == 'nothing-to-select') { - args.response.success({ - type: 'nothing-to-select', - data: { - myNetworks: [], //not used any more - sharedNetworks: [], - securityGroups: [], - networkOfferings: [] - } - }); - } - - }, - - // Step 6: Review - function(args) { - return false; - } - ], - action: function(args) { - /* - var isValid = true; - isValid &= validateString("Name", $thisPopup.find("#wizard_vm_name"), $thisPopup.find("#wizard_vm_name_errormsg"), true); //optional - isValid &= validateString("Group", $thisPopup.find("#wizard_vm_group"), $thisPopup.find("#wizard_vm_group_errormsg"), true); //optional - if (!isValid) - return; - */ - - // Create a new VM!!!! - var array1 = []; - - //step 1 : select zone - array1.push("&zoneId=" + args.data.zoneid); - - //step 2: select template - array1.push("&templateId=" + args.data.templateid); - array1.push("&hypervisor=" + selectedHypervisor); - - //step 3: select service offering - array1.push("&serviceOfferingId=" + args.data.serviceofferingid); - - //step 4: select disk offering - if(args.data.diskofferingid != null && args.data.diskofferingid != "0") { - array1.push("&diskOfferingId=" + args.data.diskofferingid); - if(selectedDiskOfferingObj.iscustomized == true) - array1.push("&size=" + args.data.size); - } - - //step 5: select network - if (step5ContainerType == 'select-network') { - var array2 = []; - var defaultNetworkId = args.data.defaultNetwork; //args.data.defaultNetwork might be equal to string "new-network" or a network ID - - var checkedNetworkIdArray; - if(typeof(args.data["my-networks"]) == "object" && args.data["my-networks"].length != null) { //args.data["my-networks"] is an array of string, e.g. ["203", "202"], - checkedNetworkIdArray = args.data["my-networks"]; - } - else if(typeof(args.data["my-networks"]) == "string" && args.data["my-networks"].length > 0) { //args.data["my-networks"] is a string, e.g. "202" - checkedNetworkIdArray = []; - checkedNetworkIdArray.push(args.data["my-networks"]); - } - else { // typeof(args.data["my-networks"]) == null - checkedNetworkIdArray = []; - } - - //create new network starts here - if(args.data["new-network"] == "create-new-network") { - var isCreateNetworkSuccessful = true; - $.ajax({ - url: createURL("createNetwork&networkOfferingId="+args.data["new-network-networkofferingid"]+"&name="+todb(args.data["new-network-name"])+"&displayText="+todb(args.data["new-network-name"])+"&zoneId="+selectedZoneObj.id), - dataType: "json", - async: false, - success: function(json) { - newNetwork = json.createnetworkresponse.network; - checkedNetworkIdArray.push(newNetwork.id); - if(defaultNetworkId == "new-network") - defaultNetworkId = newNetwork.id; - }, - error: function(XMLHttpResponse) { - isCreateNetworkSuccessful = false; - var errorMsg = "Failed to create new network, unable to proceed to deploy VM. Error: " + parseXMLHttpResponse(XMLHttpResponse); - //alert(errorMsg); - args.response.error(errorMsg); //args.response.error(errorMsg) here doesn't show errorMsg. Waiting for Brian to fix it. use alert(errorMsg) to show errorMsg for now. - } - }); - if(isCreateNetworkSuccessful == false) - return; - } - //create new network ends here - - //add default network first - if(defaultNetworkId != null && defaultNetworkId.length > 0) - array2.push(defaultNetworkId); - - //then, add other checked networks - if(checkedNetworkIdArray.length > 0) { - for(var i=0; i < checkedNetworkIdArray.length; i++) { - if(checkedNetworkIdArray[i] != defaultNetworkId) //exclude defaultNetworkId that has been added to array2 - array2.push(checkedNetworkIdArray[i]); - } - } - - array1.push("&networkIds=" + array2.join(",")); - } - else if (step5ContainerType == 'select-security-group') { - var checkedSecurityGroupIdArray; - if(typeof(args.data["security-groups"]) == "object" && args.data["security-groups"].length != null) { //args.data["security-groups"] is an array of string, e.g. ["2375f8cc-8a73-4b8d-9b26-50885a25ffe0", "27c60d2a-de7f-4bb7-96e5-a602cec681df","c6301d77-99b5-4e8a-85e2-3ea2ab31c342"], - checkedSecurityGroupIdArray = args.data["security-groups"]; - } - else if(typeof(args.data["security-groups"]) == "string" && args.data["security-groups"].length > 0) { //args.data["security-groups"] is a string, e.g. "2375f8cc-8a73-4b8d-9b26-50885a25ffe0" - checkedSecurityGroupIdArray = []; - checkedSecurityGroupIdArray.push(args.data["security-groups"]); - } - else { // typeof(args.data["security-groups"]) == null - checkedSecurityGroupIdArray = []; - } - - if(checkedSecurityGroupIdArray.length > 0) - array1.push("&securitygroupids=" + checkedSecurityGroupIdArray.join(",")); - } - - var displayname = args.data.displayname; - if(displayname != null && displayname.length > 0) { - array1.push("&displayname="+todb(displayname)); - array1.push("&name="+todb(displayname)); - } - - var group = args.data.groupname; - if (group != null && group.length > 0) - array1.push("&group="+todb(group)); - - //array1.push("&startVm=false"); //for testing only, comment it out before checking in - - $.ajax({ - url: createURL("deployVirtualMachine"+array1.join("")), - dataType: "json", - success: function(json) { - var jid = json.deployvirtualmachineresponse.jobid; - var vmid = json.deployvirtualmachineresponse.id; - args.response.success( - {_custom: - {jobId: jid, - getUpdatedItem: function(json) { - var item = json.queryasyncjobresultresponse.jobresult.virtualmachine; - if (item.password != null) - alert("Password of new VM " + item.displayname + " is " + item.password); - return item; - }, - getActionFilter: function() { - return vmActionfilter; - }, - getUpdatedItemWhenAsyncJobFails: function() { - var item; - $.ajax({ - url: createURL("listVirtualMachines&id="+vmid), - dataType: "json", - async: false, - success: function(json) { - item = json.listvirtualmachinesresponse.virtualmachine[0]; - } - }); - return item; - } - } - } - ); - }, - error: function(XMLHttpResponse) { - args.response.error(parseXMLHttpResponse(XMLHttpResponse)); //wait for Brian to implement - } - }); - } - }) + custom: cloudStack.uiCustom.instanceWizard(cloudStack.instanceWizard) }, messages: { diff --git a/ui/scripts/network.js b/ui/scripts/network.js index 597186ee257..150ade27846 100644 --- a/ui/scripts/network.js +++ b/ui/scripts/network.js @@ -177,7 +177,7 @@ } }); - var sectionsToShow = ['networks']; + var sectionsToShow = ['networks', 'vpc']; if(havingSecurityGroupNetwork == true) sectionsToShow.push('securityGroups'); @@ -3105,6 +3105,91 @@ } } } + }, + vpc: { + type: 'select', + title: 'VPC', + id: 'vpc', + listView: { + id: 'vpc', + label: 'VPC', + fields: { + name: { label: 'Name' }, + zone: { label: 'Zone' }, + cidr: { label: 'CIDR' } + }, + dataProvider: function(args) { + args.response.success({ + data: [ + { + name: 'VPC 1', + zone: 'San Jose', + cidr: '0.0.0.0/0', + networkdomain: 'testdomain', + accountdomain: 'testdomain' + }, + { + name: 'VPC 2', + zone: 'San Jose', + cidr: '0.0.0.0/0', + networkdomain: 'testdomain', + accountdomain: 'testdomain' + }, + { + name: 'VPC 3', + zone: 'Cupertino', + cidr: '0.0.0.0/0', + networkdomain: 'testdomain', + accountdomain: 'testdomain' + }, + { + name: 'VPC 4', + zone: 'San Jose', + cidr: '0.0.0.0/0', + networkdomain: 'testdomain', + accountdomain: 'testdomain' + } + ] + }); + }, + actions: { + add: { + label: 'Add VPC', + createForm: { + title: 'Add new VPC', + fields: { + name: { label: 'Name', validation: { required: true } }, + zone: { + label: 'Zone', + validation: { required: true }, + select: function(args) { + args.response.success({ + data: [ + { id: 'zone1', description: 'Zone 1' }, + { id: 'zone2', description: 'Zone 2' }, + { id: 'zone3', description: 'Zone 3' } + ] + }); + } + } + } + }, + messages: { + notification: function(args) { return 'Add new VPC'; } + }, + action: function(args) { + args.response.success(); + }, + notification: { poll: function(args) { args.complete(); } } + }, + editVpc: { + label: 'Edit VPC', + action: { + custom: cloudStack.uiCustom.vpc(cloudStack.vpc) + } + } + } + } } } }; diff --git a/ui/scripts/ui-custom/instanceWizard.js b/ui/scripts/ui-custom/instanceWizard.js index 4c1d7911eb4..0dfcdf9d698 100644 --- a/ui/scripts/ui-custom/instanceWizard.js +++ b/ui/scripts/ui-custom/instanceWizard.js @@ -18,7 +18,7 @@ /** * Instance wizard */ - cloudStack.instanceWizard = function(args) { + cloudStack.uiCustom.instanceWizard = function(args) { return function(listViewArgs) { var context = listViewArgs.context; diff --git a/ui/scripts/ui-custom/vpc.js b/ui/scripts/ui-custom/vpc.js new file mode 100644 index 00000000000..3804386c656 --- /dev/null +++ b/ui/scripts/ui-custom/vpc.js @@ -0,0 +1,404 @@ +(function($, cloudStack) { + var elems = { + router: function() { + var $router = $('
  • ').addClass('tier virtual-router'); + var $title = $('').addClass('title').html('Virtual Router'); + + $router.append($title); + + // Append horizontal chart line + $router.append($('
    ').addClass('connect-line')); + + return $router; + }, + tier: function(args) { + var name = args.name; + var cidr = args.cidr; + var context = args.context; + var vmListView = args.vmListView; + var disabledActions = args.actionPreFilter ? args.actionPreFilter({ + context: context + }) : true; + var actions = $.map( + args.actions ? args.actions : {}, function(value, key) { + return { + id: key, + action: value, + isDisabled: $.isArray(disabledActions) && + $.inArray(key, disabledActions) != -1 + }; + } + ); + var isPlaceholder = args.isPlaceholder; + var virtualMachines = args.virtualMachines; + var $tier = $('
  • ').addClass('tier'); + var $title = $('').addClass('title'); + var $cidr = $('').addClass('cidr'); + var $vmCount = $('').addClass('vm-count'); + var $actions = $('
    ').addClass('actions'); + + // Ignore special actions + // -- Add tier action is handled separately + actions = $.grep(actions, function(action) { + return action.id != 'add'; + }); + + // VM count shows instance list + $vmCount.click(function() { + var $dialog = $('
    '); + var $listView = $('
    ').listView($.extend(true, {}, vmListView, { + context: context + })); + + $dialog.append($listView); + $dialog.dialog({ + title: 'VMs in this tier', + dialogClass: 'multi-edit-add-list panel configure-acl', + width: 825, + height: 600, + buttons: { + 'Done': function() { + $(':ui-dialog').remove(); + $('.overlay').remove(); + } + } + }).closest('.ui-dialog').overlay(); + }); + + if (isPlaceholder) { + $tier.addClass('placeholder'); + $title.html('Create Tier'); + } else { + $title.html(name); + $cidr.html(cidr); + $vmCount.append( + $('').addClass('total').html(virtualMachines.length), + ' VMs' + ); + $tier.append($actions); + + // Build action buttons + $(actions).map(function(index, action) { + var $action = $('
    ').addClass('action'); + var shortLabel = action.action.shortLabel; + var label = action.action.label; + var isDisabled = action.isDisabled; + + $action.addClass(action.id); + + if (action.id != 'remove') { + $action.append($('').addClass('label').html(shortLabel)); + } else { + $action.append($('').addClass('icon').html(' ')); + } + $actions.append($action); + $action.attr('title', label); + + if (isDisabled) $action.addClass('disabled'); + + // Action event + $action.click(function() { + if (isDisabled) { + return false; + } + + tierAction({ + action: action, + context: context, + $tier: $tier + }); + + return true; + }); + }); + } + + $tier.prepend($title); + + if (!isPlaceholder) { + $tier.append($title, $cidr, $vmCount); + } + + // Append horizontal chart line + $tier.append($('
    ').addClass('connect-line')); + + return $tier; + }, + chart: function(args) { + var tiers = args.tiers; + var vmListView = args.vmListView; + var actions = args.actions; + var actionPreFilter = args.actionPreFilter; + var vpcName = args.vpcName; + var context = args.context; + var $tiers = $('
      ').addClass('tiers'); + var $router = elems.router(); + var $chart = $('
      ').addClass('vpc-chart'); + var $title = $('
      ').addClass('vpc-title').html(vpcName); + + var showAddTierDialog = function() { + if ($(this).find('.loading-overlay').size()) { + return false; + } + + addTierDialog({ + $tiers: $tiers, + context: context, + actions: actions, + vmListView: vmListView, + actionPreFilter: actionPreFilter + }); + + return true; + }; + + if (tiers.length) { + $(tiers).map(function(index, tier) { + var $tier = elems.tier({ + name: tier.name, + cidr: tier.cidr, + virtualMachines: tier.virtualMachines, + vmListView: vmListView, + actions: actions, + actionPreFilter: actionPreFilter, + context: $.extend(true, {}, context, { + tiers: [tier] + }) + }); + + $tier.appendTo($tiers); + }); + + } + + elems.tier({ isPlaceholder: true }).appendTo($tiers) + .click(showAddTierDialog); + $tiers.prepend($router); + $chart.append($title, $tiers); + + if (!tiers || !tiers.length) { + showAddTierDialog(); + } + + return $chart; + } + }; + + // Handles tier action, including UI effects + var tierAction = function(args) { + var $tier = args.$tier; + var $loading = $('
      ').addClass('loading-overlay'); + var actionArgs = args.action.action; + var action = actionArgs.action; + var actionID = args.action.id; + var notification = actionArgs.notification; + var label = actionArgs.label; + var context = args.context; + + var success = function(args) { + var remove = args ? args.remove : false; + + cloudStack.ui.notifications.add( + // Notification + { + desc: label, + poll: notification.poll + }, + + // Success + function(args) { + if (remove) { + $tier.remove(); + } else { + $loading.remove(); + } + + if (actionID == 'addVM') { + // Increment VM total + var $total = $tier.find('.vm-count .total'); + var prevTotal = parseInt($total.html()); + var newTotal = prevTotal + 1; + + $total.html(newTotal); + } + }, + + {}, + + // Error + function(args) { + $loading.remove(); + } + ); + }; + + switch(actionID) { + case 'addVM': + action({ + context: context, + complete: function(args) { + $loading.appendTo($tier); + success(args); + } + }); + break; + case 'remove': + $loading.appendTo($tier); + action({ + context: context, + response: { + success: function(args) { + success({ remove: true }); + } + } + }); + break; + case 'acl': + // Show ACL dialog + $('
      ').multiEdit( + $.extend(true, {}, actionArgs.multiEdit, { + context: context + }) + ).dialog({ + title: 'Configure ACL', + dialogClass: 'configure-acl', + width: 820, + height: 600, + buttons: { + 'Done': function() { + $(':ui-dialog').remove(); + $('.overlay').remove(); + } + } + }).closest('.ui-dialog').overlay(); + break; + default: + $loading.appendTo($tier); + action({ + context: context, + complete: success, + response: { + success: success, + error: function(args) { $loading.remove(); } + } + }); + } + }; + + // Appends a new tier to chart + var addNewTier = function(args) { + var actions = args.actions; + var vmListView = args.vmListView; + var actionPreFilter = args.actionPreFilter; + var tier = $.extend(args.tier, { + vmListView: vmListView, + actions: actions, + actionPreFilter: actionPreFilter, + virtualMachines: [] + }); + var $tiers = args.$tiers; + + $tiers.find('li.placeholder') + .before( + elems.tier(tier) + .hide() + .fadeIn('slow') + ); + }; + + // Renders the add tier form, in a dialog + var addTierDialog = function(args) { + var actions = args.actions; + var context = args.context; + var vmListView = args.vmListView; + var actionPreFilter = args.actionPreFilter; + var $tiers = args.$tiers; + + cloudStack.dialog.createForm({ + form: actions.add.createForm, + after: function(args) { + var $loading = $('
      ').addClass('loading-overlay').prependTo($tiers.find('li.placeholder')); + actions.add.action({ + context: context, + data: args.data, + response: { + success: function(args) { + var tier = args.data; + + cloudStack.ui.notifications.add( + // Notification + { + desc: actions.add.label, + poll: actions.add.notification.poll + }, + + // Success + function(args) { + $loading.remove(); + addNewTier({ + tier: tier, + $tiers: $tiers, + actions: actions, + actionPreFilter: actionPreFilter, + vmListView: vmListView + }); + }, + + {}, + + // Error + function(args) { + $loading.remove(); + } + ); + } + } + }); + } + }); + }; + + cloudStack.uiCustom.vpc = function(args) { + var vmListView = args.vmListView; + var tierArgs = args.tiers; + + return function(args) { + var context = args.context; + var $browser = $('#browser .container'); + var $toolbar = $('
      ').addClass('toolbar'); + var vpc = args.context.vpc[0]; + + $browser.cloudBrowser('addPanel', { + maximizeIfSelected: true, + title: 'Configure VPC: ' + vpc.name, + complete: function($panel) { + var $loading = $('
      ').addClass('loading-overlay').appendTo($panel); + + $panel.append($toolbar); + + // Load data + tierArgs.dataProvider({ + context: context, + response: { + success: function(args) { + var tiers = args.data.tiers; + var $chart = elems.chart({ + vmListView: vmListView, + context: context, + actions: tierArgs.actions, + actionPreFilter: tierArgs.actionPreFilter, + vpcName: vpc.name, + tiers: tiers + }).appendTo($panel); + + $loading.remove(); + $chart.fadeIn(function() { + }); + } + } + }); + } + }); + }; + }; +}(jQuery, cloudStack)); \ No newline at end of file diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js new file mode 100644 index 00000000000..a3b9afb99f3 --- /dev/null +++ b/ui/scripts/vpc.js @@ -0,0 +1,469 @@ +(function($, cloudStack) { + var aclMultiEdit = { + noSelect: true, + fields: { + 'cidrlist': { edit: true, label: 'Source CIDR' }, + 'protocol': { + label: 'Protocol', + select: function(args) { + args.$select.change(function() { + var $inputs = args.$form.find('input'); + var $icmpFields = $inputs.filter(function() { + var name = $(this).attr('name'); + + return $.inArray(name, [ + 'icmptype', + 'icmpcode' + ]) > -1; + }); + var $otherFields = $inputs.filter(function() { + var name = $(this).attr('name'); + + return name != 'icmptype' && name != 'icmpcode' && name != 'cidrlist'; + }); + + if ($(this).val() == 'icmp') { + $icmpFields.attr('disabled', false); + $otherFields.attr('disabled', 'disabled'); + } else { + $otherFields.attr('disabled', false); + $icmpFields.attr('disabled', 'disabled'); + } + }); + + args.response.success({ + data: [ + { name: 'tcp', description: 'TCP' }, + { name: 'udp', description: 'UDP' }, + { name: 'icmp', description: 'ICMP' } + ] + }); + } + }, + 'startport': { edit: true, label: 'Start Port' }, + 'endport': { edit: true, label: 'End Port' }, + 'icmptype': { edit: true, label: 'ICMP Type', isDisabled: true }, + 'icmpcode': { edit: true, label: 'ICMP Code', isDisabled: true }, + 'add-rule': { + label: 'Add', + addButton: true + } + }, + add: { + label: 'Add', + action: function(args) { + setTimeout(function() { + args.response.success({ + notification: { + label: 'Add ACL rule', + poll: function(args) { args.complete(); } + } + }); + }, 500); + } + }, + actions: { + destroy: { + label: 'Remove Rule', + action: function(args) { + setTimeout(function() { + args.response.success({ + notification: { + label: 'Remove ACL rule', + poll: function(args) { args.complete(); } + } + }); + }, 500); + } + } + }, + dataProvider: function(args) { + setTimeout(function() { + args.response.success({ + data: [ + { + "id": 11, + "protocol": "icmp", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/0", + "icmptype": 2, + "icmpcode": 22 + }, + { + "id": 10, + "protocol": "udp", + "startport": "500", + "endport": "10000", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 9, + "protocol": "tcp", + "startport": "20", + "endport": "200", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 11, + "protocol": "icmp", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/0", + "icmptype": 2, + "icmpcode": 22 + }, + { + "id": 10, + "protocol": "udp", + "startport": "500", + "endport": "10000", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 9, + "protocol": "tcp", + "startport": "20", + "endport": "200", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 11, + "protocol": "icmp", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/0", + "icmptype": 2, + "icmpcode": 22 + }, + { + "id": 10, + "protocol": "udp", + "startport": "500", + "endport": "10000", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 9, + "protocol": "tcp", + "startport": "20", + "endport": "200", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 11, + "protocol": "icmp", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/0", + "icmptype": 2, + "icmpcode": 22 + }, + { + "id": 10, + "protocol": "udp", + "startport": "500", + "endport": "10000", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 9, + "protocol": "tcp", + "startport": "20", + "endport": "200", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 11, + "protocol": "icmp", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/0", + "icmptype": 2, + "icmpcode": 22 + }, + { + "id": 10, + "protocol": "udp", + "startport": "500", + "endport": "10000", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + }, + { + "id": 9, + "protocol": "tcp", + "startport": "20", + "endport": "200", + "ipaddressid": 4, + "ipaddress": "10.223.71.23", + "state": "Active", + "cidrlist": "0.0.0.0/24" + } + ] + }); + }, 100); + } + }; + + cloudStack.vpc = { + vmListView: { + id: 'vpcTierInstances', + listView: { + filters: { + mine: { label: 'My instances' }, + all: { label: 'All instances' }, + running: { label: 'Running instances' }, + destroyed: { label: 'Destroyed instances' } + }, + fields: { + name: { label: 'Name', editable: true }, + account: { label: 'Account' }, + zonename: { label: 'Zone' }, + state: { + label: 'Status', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Destroyed': 'off' + } + } + }, + + // List view actions + actions: { + restart: { + label: 'Restart instance', + action: function(args) { + setTimeout(function() { + args.response.success({ + data: { + state: 'Restarting' + } + }); + }, 1000); + }, + messages: { + confirm: function(args) { + return 'Are you sure you want to restart ' + args.name + '?'; + }, + notification: function(args) { + return 'Rebooting VM: ' + args.name; + } + }, + notification: { + poll: function(args) { args.complete(); } + } + }, + stop: { + label: 'Stop instance', + action: function(args) { + setTimeout(function() { + args.response.success({ + data: { state: 'Stopping' } + }); + }, 500); + }, + messages: { + confirm: function(args) { + return 'Are you sure you want to shutdown ' + args.name + '?'; + }, + notification: function(args) { + return 'Rebooting VM: ' + args.name; + } + }, + notification: { + poll: function(args) { args.complete(); } + } + }, + start: { + label: 'Start instance', + action: function(args) { + setTimeout(function() { + args.response.success({ + data: { state: 'Starting' } + }); + }, 500); + }, + messages: { + confirm: function(args) { + return 'Are you sure you want to start ' + args.name + '?'; + }, + notification: function(args) { + return 'Starting VM: ' + args.name; + } + }, + notification: { + poll: function(args) { args.complete(); } + } + }, + destroy: { + label: 'Destroy instance', + messages: { + confirm: function(args) { + return 'Are you sure you want to destroy ' + args.name + '?'; + }, + notification: function(args) { + return 'Destroyed VM: ' + args.name; + } + }, + action: function(args) { + setTimeout(function() { + args.response.success({ data: { state: 'Destroying' }}); + }, 200); + }, + notification: { + poll: function(args) { args.complete(); } + } + } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listVirtualMachines'), + success: function(json) { + args.response.success({ data: json.listvirtualmachinesresponse.virtualmachine }); + } + }); + } + } + }, + tiers: { + actionPreFilter: function(args) { + return ['start']; + }, + actions: { + // Add new tier + add: { + label: 'Add new tier to VPC', + action: function(args) { + setTimeout(function() { + args.response.success({ + data: { + name: args.data.name, + cidr: args.data.cidr + } + }); + }, 500); + }, + + createForm: { + title: 'Add new tier', + desc: 'Please fill in the following to add a new VPC tier.', + fields: { + name: { label: 'label.name', validation: { required: true } }, + cidr: { label: 'label.cidr', validation: { required: true } } + } + }, + + notification: { + poll: function(args) { args.complete(); } + } + }, + start: { + label: 'Start tier', + shortLabel: 'Start', + action: function(args) { + args.response.success(); + }, + notification: { + poll: function(args) { args.complete(); } + } + }, + stop: { + label: 'Stop tier', + shortLabel: 'Stop', + action: function(args) { + args.response.success(); + }, + notification: { + poll: function(args) { args.complete(); } + } + }, + addVM: { + label: 'Add VM to tier', + shortLabel: 'Add VM', + action: cloudStack.uiCustom.instanceWizard( + cloudStack.instanceWizard + ), + notification: { + poll: function(args) { args.complete(); } + } + }, + acl: { + label: 'Configure ACL for tier', + shortLabel: 'ACL', + multiEdit: aclMultiEdit + }, + remove: { + label: 'Remove tier', + action: function(args) { + args.response.success(); + }, + notification: { + poll: function(args) { args.complete(); } + } + } + }, + + // Get tiers + dataProvider: function(args) { + var tiers = [ // Dummy content + { + id: 1, + name: 'web', + cidr: '192.168.0.0/24', + virtualMachines: [ + { name: 'i-2-VM' }, + { name: 'i-3-VM' } + ] + }, + { + id: 2, + name: 'app', + cidr: '10.0.0.0/24', + virtualMachines: [] + } + ]; + + setTimeout(function() { + args.response.success({ + data: { + tiers: tiers + } + }); + }, 1000); + } + } + }; +}(jQuery, cloudStack));