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 2ef74540bbf..52016f0cf48 100644 Binary files a/ui/images/bg-gradients.png and b/ui/images/bg-gradients.png differ diff --git a/ui/index.jsp b/ui/index.jsp index 3c377eaef02..fb3327f5466 100644 --- a/ui/index.jsp +++ b/ui/index.jsp @@ -1629,11 +1629,14 @@ + + + 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));