mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Problem: Custom compute offering does not allow setting min and max values for CPU and VRAM for custom VMs. Root Cause: Custom compute offerings cannot be created with a given range of CPU number and memory instead it allows only fixed values. Solution: createServiceOffering API has been modified to allow setting a defined range for CPU number and memory. Also, UI form for compute offering creation is provided with a new field named 'compute offering type’ with values - Fixed, Custom Constrained, Custom Constrained. It will allow the creation of compute offerings either with a fixed CPU speed and memory for fixed compute offering, or with a range of CPU number and memory for custom constrained compute offering or without predefined CPU number, CPU speed and memory for custom unconstrained compute offering. To allow the user to set CPU number, CPU speed and memory during VM deployment, UI form for VM deployment has been modified to provide controls to change these values. These controls are depicted in screenshots below for custom constrained and custom unconstrained compute offering types. Sample API calls using cmk to create a constrained service offering and deploying a VM using it, create serviceoffering name=Constrained displaytext=Constrained customized=true mincpunumber=2 maxcpunumber=4 cpuspeed=400 minmemory=256 maxmemory=1024 deploy virtualmachine displayname=ConstrainedVM serviceofferingid=60f3e500-6559-40b2-9a61-2192891c2bd6 templateid=8e0f4a3e-601b-11e9-9df4-a0afbd4a2d60 zoneid=9612a0c6-ed28-4fae-9a48-6eb207af29e3 details[0].cpuNumber=3 details[0].memory=800 Signed-off-by: Abhishek Kumar <abhishek.kumar@shapeblue.com>
1161 lines
56 KiB
JavaScript
1161 lines
56 KiB
JavaScript
// Licensed to the Apache Software Foundation (ASF) under one
|
|
// or more contributor license agreements. See the NOTICE file
|
|
// distributed with this work for additional information
|
|
// regarding copyright ownership. The ASF licenses this file
|
|
// to you under the Apache License, Version 2.0 (the
|
|
// "License"); you may not use this file except in compliance
|
|
// with the License. You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing,
|
|
// software distributed under the License is distributed on an
|
|
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
// KIND, either express or implied. See the License for the
|
|
// specific language governing permissions and limitations
|
|
// under the License.
|
|
|
|
(function($, cloudStack) {
|
|
var zoneObjs, hypervisorObjs, featuredTemplateObjs, communityTemplateObjs, myTemplateObjs, sharedTemplateObjs, featuredIsoObjs, communityIsoObjs, myIsoObjs, sharedIsoObjs, serviceOfferingObjs, community, networkObjs;
|
|
var selectedZoneObj, selectedTemplateObj, selectedHypervisor, selectedDiskOfferingObj;
|
|
var selectedTemplateOrIso; //'select-template', 'select-iso'
|
|
var step6ContainerType = 'nothing-to-select'; //'nothing-to-select', 'select-network', 'select-security-group', 'select-advanced-sg'(advanced sg-enabled zone)
|
|
|
|
cloudStack.instanceWizard = {
|
|
//min disk offering size when custom disk size is used
|
|
minDiskOfferingSize: function() {
|
|
return g_capabilities.customdiskofferingminsize;
|
|
},
|
|
|
|
//max disk offering size when custom disk size is used
|
|
maxDiskOfferingSize: function() {
|
|
return g_capabilities.customdiskofferingmaxsize;
|
|
},
|
|
|
|
// Determines whether 'add new network' box is shown.
|
|
// -- return true to show, false to hide
|
|
showAddNetwork: function(args) {
|
|
return true;
|
|
},
|
|
|
|
// Called in networks list, when VPC drop-down is changed
|
|
// -- if vpcID given, return true if in network specified by vpcID
|
|
// -- if vpcID == -1, always show all networks
|
|
vpcFilter: function(data, vpcID) {
|
|
return vpcID != -1 ?
|
|
data.vpcid == vpcID : true;
|
|
},
|
|
|
|
// Runs when advanced SG-enabled zone is run, before
|
|
// the security group step
|
|
//
|
|
// -- if it returns false, then 'Select Security Group' is skipped.
|
|
//
|
|
advSGFilter: function(args) {
|
|
var selectedNetworks;
|
|
|
|
if ($.isArray(args.data['my-networks'])) {
|
|
selectedNetworks = $(args.data['my-networks']).map(function(index, myNetwork) {
|
|
return $.grep(networkObjs, function(networkObj) {
|
|
return networkObj.id == myNetwork;
|
|
});
|
|
});
|
|
} else {
|
|
selectedNetworks = $.grep(networkObjs, function(networkObj) {
|
|
return networkObj.id == args.data['my-networks'];
|
|
});
|
|
}
|
|
|
|
return $.grep(selectedNetworks, function(network) {
|
|
return $.grep(network.service, function(service) {
|
|
return service.name == 'SecurityGroup';
|
|
}).length;
|
|
}).length; //return total number of selected sg networks
|
|
},
|
|
|
|
// Data providers for each wizard step
|
|
steps: [
|
|
// Step 1: Setup
|
|
function(args) {
|
|
//from VPC Tier chart -- when the tier (network) has strechedl2subnet==false:
|
|
//only own zone is populated to the dropdown
|
|
if (args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard"
|
|
&& args.context.networks[0].strechedl2subnet) {
|
|
zoneObjs = [{
|
|
id: args.context.vpc[0].zoneid,
|
|
name: args.context.vpc[0].zonename,
|
|
networktype: 'Advanced'
|
|
}];
|
|
args.response.success({
|
|
data: {
|
|
zones: zoneObjs
|
|
}
|
|
});
|
|
}
|
|
//in all other cases (as well as from instance page) all zones are populated to dropdown
|
|
else {
|
|
$.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) *****
|
|
selectedTemplateOrIso = args.currentData['select-template'];
|
|
if (selectedTemplateOrIso == '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) {
|
|
if (json.listtemplatesresponse.template == null) {
|
|
featuredTemplateObjs = null;
|
|
} else {
|
|
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) {
|
|
if (json.listtemplatesresponse.template == null) {
|
|
communityTemplateObjs = null;
|
|
} else {
|
|
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) {
|
|
if (json.listtemplatesresponse.template == null) {
|
|
myTemplateObjs = null;
|
|
} else {
|
|
myTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) {
|
|
if ($.inArray(item.hypervisor, hypervisorArray) > -1)
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
});
|
|
$.ajax({
|
|
url: createURL("listTemplates&templatefilter=sharedexecutable&zoneid=" + args.currentData.zoneid),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
if (json.listtemplatesresponse.template == null) {
|
|
sharedTemplateObjs = null;
|
|
} else {
|
|
sharedTemplateObjs = $.grep(json.listtemplatesresponse.template, function(item, index) {
|
|
if ($.inArray(item.hypervisor, hypervisorArray) > -1)
|
|
return true;
|
|
});
|
|
}
|
|
}
|
|
});
|
|
} else if (selectedTemplateOrIso == 'select-iso') {
|
|
$.ajax({
|
|
url: createURL("listIsos&isofilter=featured&zoneid=" + args.currentData.zoneid + "&bootable=true"),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
if (json.listisosresponse.iso == null) {
|
|
featuredIsoObjs = null;
|
|
} else {
|
|
featuredIsoObjs = json.listisosresponse.iso;
|
|
}
|
|
}
|
|
});
|
|
$.ajax({
|
|
url: createURL("listIsos&isofilter=community&zoneid=" + args.currentData.zoneid + "&bootable=true"),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
if (json.listisosresponse.iso == null) {
|
|
communityIsoObjs = null;
|
|
} else {
|
|
communityIsoObjs = json.listisosresponse.iso;
|
|
}
|
|
}
|
|
});
|
|
$.ajax({
|
|
url: createURL("listIsos&isofilter=selfexecutable&zoneid=" + args.currentData.zoneid + "&bootable=true"),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
if (json.listisosresponse.iso == null) {
|
|
myIsoObjs = null;
|
|
} else {
|
|
myIsoObjs = json.listisosresponse.iso;
|
|
}
|
|
}
|
|
});
|
|
$.ajax({
|
|
url: createURL("listIsos&isofilter=sharedexecutable&zoneid=" + args.currentData.zoneid + "&bootable=true"),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
if (json.listisosresponse.iso == null) {
|
|
sharedIsoObjs = null;
|
|
} else {
|
|
sharedIsoObjs = json.listisosresponse.iso;
|
|
}
|
|
}
|
|
});
|
|
}
|
|
//***** get templates/ISOs (end) *****
|
|
|
|
|
|
var templatesObj = {};
|
|
if (selectedTemplateOrIso == 'select-template') {
|
|
templatesObj = {
|
|
featuredtemplates: featuredTemplateObjs,
|
|
communitytemplates: communityTemplateObjs,
|
|
mytemplates: myTemplateObjs,
|
|
sharedtemplates: sharedTemplateObjs
|
|
};
|
|
} else if (selectedTemplateOrIso == 'select-iso') {
|
|
templatesObj = {
|
|
featuredisos: featuredIsoObjs,
|
|
communityisos: communityIsoObjs,
|
|
myisos: myIsoObjs,
|
|
sharedisos: sharedIsoObjs
|
|
};
|
|
}
|
|
args.response.success({
|
|
hypervisor: {
|
|
idField: 'name',
|
|
nameField: 'name'
|
|
},
|
|
data: {
|
|
templates: templatesObj,
|
|
hypervisors: hypervisorObjs
|
|
},
|
|
customHidden: function(args) {
|
|
if (selectedTemplateOrIso == 'select-template') {
|
|
return false; //show Root Disk Size field
|
|
} else { //selectedTemplateOrIso == 'select-iso'
|
|
return true; //hide Root Disk Size field
|
|
}
|
|
}
|
|
});
|
|
},
|
|
|
|
// Step 3: Service offering
|
|
function(args) {
|
|
selectedTemplateObj = null; //reset
|
|
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) {
|
|
if (sharedTemplateObjs != null && sharedTemplateObjs.length > 0) {
|
|
for (var i = 0; i < sharedTemplateObjs.length; i++) {
|
|
if (sharedTemplateObjs[i].id == args.currentData.templateid) {
|
|
selectedTemplateObj = sharedTemplateObjs[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;
|
|
}
|
|
|
|
// if the user is leveraging a template, then we can show custom IOPS, if applicable
|
|
var canShowCustomIopsForServiceOffering = (args.currentData["select-template"] != "select-iso" ? true : false);
|
|
|
|
|
|
// get serviceOfferingObjs
|
|
$(window).removeData("cloudStack.module.instanceWizard.serviceOfferingObjs");
|
|
$(window).trigger("cloudStack.module.instanceWizard.serviceOffering.dataProvider", {
|
|
context: args.context,
|
|
currentData: args.currentData
|
|
});
|
|
if ($(window).data("cloudStack.module.instanceWizard.serviceOfferingObjs") == undefined) {
|
|
$.ajax({
|
|
url: createURL("listServiceOfferings&issystem=false"),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
serviceOfferingObjs = json.listserviceofferingsresponse.serviceoffering;
|
|
}
|
|
});
|
|
} else {
|
|
serviceOfferingObjs = $(window).data("cloudStack.module.instanceWizard.serviceOfferingObjs");
|
|
}
|
|
|
|
|
|
args.response.success({
|
|
canShowCustomIops: canShowCustomIopsForServiceOffering,
|
|
customFlag: 'iscustomized',
|
|
//customFlag: 'offerha', //for testing only
|
|
customIopsFlag: 'iscustomizediops',
|
|
data: {
|
|
serviceOfferings: serviceOfferingObjs
|
|
}
|
|
});
|
|
},
|
|
|
|
// Step 4: Data disk offering
|
|
function(args) {
|
|
var isRequired = (args.currentData["select-template"] == "select-iso" ? true : false);
|
|
var templateFilter = 'executable'
|
|
if (isAdmin()) {
|
|
templateFilter = 'all'
|
|
}
|
|
$.ajax({
|
|
url: createURL("listDiskOfferings"),
|
|
dataType: "json",
|
|
async: true,
|
|
success: function(json) {
|
|
diskOfferingObjs = json.listdiskofferingsresponse.diskoffering;
|
|
var multiDisks = false;
|
|
if (!isRequired) {
|
|
$.ajax({
|
|
url: createURL("listTemplates"),
|
|
data: {
|
|
id: args.currentData.templateid,
|
|
templatefilter: templateFilter
|
|
},
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
var templateDataDisks = json.listtemplatesresponse.template[0].childtemplates;
|
|
var count = 0; if (templateDataDisks && Object.keys(templateDataDisks).length > 0) {
|
|
multiDisks = [];
|
|
$.each(templateDataDisks, function(index, item) {
|
|
count = count + 1;
|
|
multiDisks.push({
|
|
id: item.id,
|
|
label: item.name,
|
|
size: item.size,
|
|
});
|
|
});
|
|
if (count == 0){
|
|
multiDisks.push({
|
|
id: "none",
|
|
label: "No datadisk found",
|
|
size: "0"
|
|
});
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
args.response.success({
|
|
required: isRequired,
|
|
customFlag: 'iscustomized', // Field determines if custom slider is shown
|
|
customIopsDoFlag: 'iscustomizediops',
|
|
data: {
|
|
diskOfferings: diskOfferingObjs
|
|
},
|
|
multiDisk: multiDisks
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// Step 5: Affinity
|
|
function(args) {
|
|
$.ajax({
|
|
url: createURL('listAffinityGroups'),
|
|
success: function(json) {
|
|
var affinitygroups = json.listaffinitygroupsresponse.affinitygroup;
|
|
var data = {
|
|
affinityGroups: affinitygroups
|
|
};
|
|
|
|
if(selectedZoneObj.domainid != null && selectedZoneObj.affinitygroupid != null) {
|
|
var defaultAffinityGroup;
|
|
if(affinitygroups != null) {
|
|
for(var i = 0; i < affinitygroups.length; i++) {
|
|
if(affinitygroups[i].id == selectedZoneObj.affinitygroupid) {
|
|
defaultAffinityGroup = affinitygroups[i];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
$.extend(data, {
|
|
selectedObj: defaultAffinityGroup,
|
|
selectedObjNonEditable: true
|
|
});
|
|
}
|
|
|
|
args.response.success({
|
|
data: data
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// Step 6: 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.
|
|
var $networkStep = $(".step.network:visible .nothing-to-select");
|
|
var $networkStepContainer = $('.step.network:visible');
|
|
|
|
if (args.initArgs.pluginForm != null && args.initArgs.pluginForm.name == "vpcTierInstanceWizard") { //from VPC Tier chart
|
|
step6ContainerType = 'nothing-to-select';
|
|
$networkStep.find("#from_instance_page_1").hide();
|
|
$networkStep.find("#from_instance_page_2").hide();
|
|
$networkStep.find("#from_vpc_tier").prepend("tier " + _s(args.context.networks[0].name));
|
|
$networkStep.find("#from_vpc_tier").show();
|
|
} else { //from Instance page
|
|
if (selectedZoneObj.securitygroupsenabled != true) { // Advanced SG-disabled zone
|
|
step6ContainerType = 'select-network';
|
|
$networkStep.find("#from_instance_page_1").show();
|
|
$networkStep.find("#from_instance_page_2").show();
|
|
$networkStep.find("#from_vpc_tier").text("");
|
|
$networkStep.find("#from_vpc_tier").hide();
|
|
$networkStepContainer.removeClass('next-use-security-groups');
|
|
} else { // Advanced SG-enabled zone
|
|
step6ContainerType = 'select-advanced-sg';
|
|
}
|
|
|
|
if ($networkStepContainer.hasClass('next-use-security-groups')) {
|
|
$networkStepContainer.removeClass('repeat next-use-security-groups loaded');
|
|
step6ContainerType = 'select-security-group';
|
|
}
|
|
}
|
|
} 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") {
|
|
step6ContainerType = 'nothing-to-select';
|
|
} else {
|
|
step6ContainerType = 'select-security-group';
|
|
}
|
|
}
|
|
|
|
//step6ContainerType = 'nothing-to-select'; //for testing only, comment it out before checking in
|
|
if (step6ContainerType == 'select-network' || step6ContainerType == 'select-advanced-sg') {
|
|
var defaultNetworkArray = [],
|
|
optionalNetworkArray = [];
|
|
var networkData = {
|
|
zoneId: args.currentData.zoneid,
|
|
canusefordeploy: true
|
|
};
|
|
|
|
if (selectedZoneObj.networktype == 'Advanced' && selectedZoneObj.securitygroupsenabled == true) {
|
|
$.extend(networkData, {
|
|
type: 'Shared'
|
|
});
|
|
}
|
|
|
|
if (!(cloudStack.context.projects && cloudStack.context.projects[0])) {
|
|
networkData.domainid = g_domainid;
|
|
networkData.account = g_account;
|
|
}
|
|
|
|
var vpcObjs;
|
|
|
|
//listVPCs without account/domainid/listAll parameter will return only VPCs belonging to the current login. That's what should happen in Instances page's VM Wizard.
|
|
//i.e. If the current login is root-admin, do not show VPCs belonging to regular-user/domain-admin in Instances page's VM Wizard.
|
|
$.ajax({
|
|
url: createURL('listVPCs'),
|
|
async: false,
|
|
success: function(json) {
|
|
vpcObjs = json.listvpcsresponse.vpc ? json.listvpcsresponse.vpc : [];
|
|
}
|
|
});
|
|
|
|
var networkObjsToPopulate = [];
|
|
$.ajax({
|
|
url: createURL('listNetworks'),
|
|
data: networkData,
|
|
async: false,
|
|
success: function(json) {
|
|
networkObjs = json.listnetworksresponse.network ? json.listnetworksresponse.network : [];
|
|
if (networkObjs.length > 0) {
|
|
for (var i = 0; i < networkObjs.length; i++) {
|
|
var networkObj = networkObjs[i];
|
|
var includingSecurityGroup = false;
|
|
var serviceObjArray = networkObj.service;
|
|
for (var k = 0; k < serviceObjArray.length; k++) {
|
|
if (serviceObjArray[k].name == "SecurityGroup") {
|
|
networkObjs[i].type = networkObjs[i].type + ' (sg)';
|
|
includingSecurityGroup = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (networkObj.vpcid) {
|
|
networkObj._singleSelect = true;
|
|
}
|
|
|
|
//for Advanced SG-enabled zone, list only SG network offerings
|
|
if (selectedZoneObj.networktype == 'Advanced' && selectedZoneObj.securitygroupsenabled == true) {
|
|
if (includingSecurityGroup == false)
|
|
continue; //skip to next network offering
|
|
}
|
|
networkObjsToPopulate.push(networkObj);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
|
|
//In addition to the networks in the current zone, find networks in other zones that have stretchedL2subnet==true
|
|
//capability and show them on the UI
|
|
var allOtherAdvancedZones = [];
|
|
$.ajax({
|
|
url: createURL('listZones'),
|
|
dataType: "json",
|
|
async: false,
|
|
success: function(json) {
|
|
var result = $.grep(json.listzonesresponse.zone, function(zone) {
|
|
return (zone.networktype == 'Advanced');
|
|
});
|
|
$(result).each(function() {
|
|
if (selectedZoneObj.id != this.id)
|
|
allOtherAdvancedZones.push(this);
|
|
});
|
|
}
|
|
});
|
|
if (allOtherAdvancedZones.length > 0) {
|
|
for (var i = 0; i < allOtherAdvancedZones.length; i++) {
|
|
var networkDataForZone = {
|
|
zoneId: allOtherAdvancedZones[i].id,
|
|
canusefordeploy: true
|
|
};
|
|
$.ajax({
|
|
url: createURL('listNetworks'),
|
|
data: networkDataForZone,
|
|
async: false,
|
|
success: function(json) {
|
|
var networksInThisZone = json.listnetworksresponse.network ? json.listnetworksresponse.network : [];
|
|
if (networksInThisZone.length > 0) {
|
|
for (var i = 0; i < networksInThisZone.length; i++) {
|
|
if (networksInThisZone[i].strechedl2subnet) {
|
|
networkObjsToPopulate.push(networksInThisZone[i]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
|
|
// get networkObjsToPopulate
|
|
$(window).removeData("cloudStack.module.instanceWizard.networkObjs");
|
|
$(window).trigger("cloudStack.module.instanceWizard.network.dataProvider", {
|
|
context: args.context,
|
|
currentData: args.currentData,
|
|
networkObjsToPopulate: networkObjsToPopulate
|
|
});
|
|
if ($(window).data("cloudStack.module.instanceWizard.networkObjs") == undefined) {
|
|
//do nothing
|
|
} else {
|
|
networkObjsToPopulate = $(window).data("cloudStack.module.instanceWizard.networkObjs"); //override networkObjsToPopulate
|
|
}
|
|
|
|
|
|
$.ajax({
|
|
url: createURL("listNetworkOfferings"),
|
|
dataType: "json",
|
|
data: {
|
|
forvpc: false,
|
|
zoneid: args.currentData.zoneid,
|
|
guestiptype: 'Isolated',
|
|
supportedServices: 'SourceNat',
|
|
specifyvlan: false,
|
|
state: 'Enabled'
|
|
},
|
|
async: false,
|
|
success: function(json) {
|
|
networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering;
|
|
}
|
|
});
|
|
//get network offerings (end) ***
|
|
|
|
$networkStepContainer.removeClass('repeat next-use-security-groups');
|
|
|
|
if (step6ContainerType == 'select-advanced-sg') {
|
|
$networkStepContainer.addClass('repeat next-use-security-groups');
|
|
|
|
// Add guest network is disabled
|
|
$networkStepContainer.find('.select-network').addClass('no-add-network');
|
|
} else {
|
|
$networkStepContainer.find('.select-network').removeClass('no-add-network');
|
|
}
|
|
|
|
args.response.success({
|
|
type: 'select-network',
|
|
data: {
|
|
networkObjs: networkObjsToPopulate,
|
|
securityGroups: [],
|
|
networkOfferings: networkOfferingObjs,
|
|
vpcs: vpcObjs
|
|
}
|
|
});
|
|
} else if (step6ContainerType == '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++) {
|
|
securityGroupArray.push(items[i]);
|
|
}
|
|
securityGroupArray.sort(function(a, b){
|
|
if(a.name < b.name) return -1;
|
|
if(a.name > b.name) return 1;
|
|
return 0;
|
|
})
|
|
}
|
|
}
|
|
});
|
|
args.response.success({
|
|
type: 'select-security-group',
|
|
data: {
|
|
networkObjs: [],
|
|
securityGroups: securityGroupArray,
|
|
networkOfferings: [],
|
|
vpcs: []
|
|
}
|
|
});
|
|
} else if (step6ContainerType == 'nothing-to-select') {
|
|
args.response.success({
|
|
type: 'nothing-to-select',
|
|
data: {
|
|
networkObjs: [],
|
|
securityGroups: [],
|
|
networkOfferings: [],
|
|
vpcs: []
|
|
}
|
|
});
|
|
}
|
|
|
|
},
|
|
|
|
// Step 7: SSH Key Pairs
|
|
function(args) {
|
|
$.ajax({
|
|
url: createURL('listSSHKeyPairs'),
|
|
success: function(json) {
|
|
var sshkeypair = json.listsshkeypairsresponse.sshkeypair;
|
|
args.response.success({
|
|
data: {
|
|
sshkeyPairs: sshkeypair
|
|
}
|
|
});
|
|
}
|
|
});
|
|
},
|
|
|
|
// Step 8: Review
|
|
function(args) {
|
|
return false;
|
|
}
|
|
],
|
|
action: function(args) {
|
|
// Create a new VM!!!!
|
|
var deployVmData = {};
|
|
|
|
//step 1 : select zone
|
|
$.extend(deployVmData, {
|
|
zoneid : args.data.zoneid
|
|
});
|
|
|
|
//step 2: select template
|
|
$.extend(deployVmData, {
|
|
templateid : args.data.templateid
|
|
});
|
|
|
|
$.extend(deployVmData, {
|
|
hypervisor : selectedHypervisor
|
|
});
|
|
|
|
if (args.$wizard.find('input[name=rootDiskSize]').parent().css('display') != 'none') {
|
|
if (args.$wizard.find('input[name=rootDiskSize]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
rootdisksize : args.$wizard.find('input[name=rootDiskSize]').val()
|
|
});
|
|
}
|
|
}
|
|
|
|
//step 3: select service offering
|
|
$.extend(deployVmData, {
|
|
serviceofferingid : args.data.serviceofferingid
|
|
});
|
|
|
|
if (args.$wizard.find('input[name=compute-cpu-cores]').parent().parent().css('display') != 'none') {
|
|
if (args.$wizard.find('input[name=compute-cpu-cores]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].cpuNumber' : args.$wizard.find('input[name=compute-cpu-cores]').val()
|
|
});
|
|
}
|
|
if (args.$wizard.find('input[name=compute-cpu]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].cpuSpeed' : args.$wizard.find('input[name=compute-cpu]').val()
|
|
});
|
|
}
|
|
if (args.$wizard.find('input[name=compute-memory]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].memory' : args.$wizard.find('input[name=compute-memory]').val()
|
|
});
|
|
}
|
|
} else if (args.$wizard.find('input[name=slider-compute-cpu-cores]').parent().parent().css('display') != 'none') {
|
|
if (args.$wizard.find('input[name=slider-compute-cpu-cores]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].cpuNumber' : args.$wizard.find('input[name=slider-compute-cpu-cores]').val()
|
|
});
|
|
}
|
|
if (args.$wizard.find('input[name=slider-compute-memory]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].memory' : args.$wizard.find('input[name=slider-compute-memory]').val()
|
|
});
|
|
}
|
|
}
|
|
|
|
if (args.$wizard.find('input[name=disk-min-iops]').parent().parent().css('display') != 'none') {
|
|
if (args.$wizard.find('input[name=disk-min-iops]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].minIops' : args.$wizard.find('input[name=disk-min-iops]').val()
|
|
});
|
|
}
|
|
if (args.$wizard.find('input[name=disk-max-iops]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].maxIops' : args.$wizard.find('input[name=disk-max-iops]').val()
|
|
});
|
|
}
|
|
}
|
|
|
|
//step 4: select disk offering
|
|
if (args.data.diskofferingid != null && args.data.diskofferingid != "0") {
|
|
$.extend(deployVmData, {
|
|
diskofferingid : args.data.diskofferingid
|
|
});
|
|
|
|
if (selectedDiskOfferingObj.iscustomized == true) {
|
|
$.extend(deployVmData, {
|
|
size : args.data.size
|
|
});
|
|
}
|
|
|
|
if (selectedDiskOfferingObj.iscustomizediops == true) {
|
|
if (args.$wizard.find('input[name=disk-min-iops-do]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].minIopsDo' : args.$wizard.find('input[name=disk-min-iops-do]').val()
|
|
});
|
|
}
|
|
|
|
if (args.$wizard.find('input[name=disk-max-iops-do]').val().length > 0) {
|
|
$.extend(deployVmData, {
|
|
'details[0].maxIopsDo' : args.$wizard.find('input[name=disk-max-iops-do]').val()
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
if (args.data["disk-offerings-multi"] != null && args.data["disk-offerings-multi"].length > 0) {
|
|
$(args.data["disk-offerings-multi"]).each(function(index, disk) {
|
|
var diskMap = {};
|
|
diskMap['datadiskofferinglist[' + index + '].datadisktemplateid'] = disk.id;
|
|
diskMap['datadiskofferinglist[' + index + '].diskofferingid'] = disk._diskOfferingId;
|
|
$.extend(deployVmData, diskMap);
|
|
});
|
|
}
|
|
|
|
//step 5: select an affinity group
|
|
var checkedAffinityGroupIdArray;
|
|
if (typeof(args.data["affinity-groups"]) == "object" && args.data["affinity-groups"].length != null) { //args.data["affinity-groups"] is an array of string, e.g. ["2375f8cc-8a73-4b8d-9b26-50885a25ffe0", "27c60d2a-de7f-4bb7-96e5-a602cec681df","c6301d77-99b5-4e8a-85e2-3ea2ab31c342"],
|
|
checkedAffinityGroupIdArray = args.data["affinity-groups"];
|
|
} else if (typeof(args.data["affinity-groups"]) == "string" && args.data["affinity-groups"].length > 0) { //args.data["affinity-groups"] is a string, e.g. "2375f8cc-8a73-4b8d-9b26-50885a25ffe0"
|
|
checkedAffinityGroupIdArray = [];
|
|
checkedAffinityGroupIdArray.push(args.data["affinity-groups"]);
|
|
} else { // typeof(args.data["affinity-groups"]) == null
|
|
checkedAffinityGroupIdArray = [];
|
|
}
|
|
|
|
if (checkedAffinityGroupIdArray.length > 0) {
|
|
$.extend(deployVmData, {
|
|
affinitygroupids : checkedAffinityGroupIdArray.join(",")
|
|
});
|
|
}
|
|
|
|
//step 6: select network
|
|
if (step6ContainerType == 'select-network' || step6ContainerType == 'select-advanced-sg') {
|
|
var array2 = [];
|
|
var array3 = [];
|
|
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;
|
|
|
|
var createNetworkData = {
|
|
networkOfferingId: args.data["new-network-networkofferingid"],
|
|
name: args.data["new-network-name"],
|
|
displayText: args.data["new-network-name"],
|
|
zoneId: selectedZoneObj.id
|
|
};
|
|
|
|
$.ajax({
|
|
url: createURL('createNetwork'),
|
|
data: createNetworkData,
|
|
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
|
|
|
|
|
|
if (defaultNetworkId == null) {
|
|
cloudStack.dialog.notice({
|
|
message: "Please select a default network in Network step."
|
|
});
|
|
return;
|
|
}
|
|
|
|
if (checkedNetworkIdArray.length > 0) {
|
|
for (var i = 0; i < checkedNetworkIdArray.length; i++) {
|
|
if (checkedNetworkIdArray[i] == defaultNetworkId) {
|
|
array2.unshift(defaultNetworkId);
|
|
|
|
var ipToNetwork = {
|
|
networkid: defaultNetworkId
|
|
};
|
|
if (args.data["new-network"] == "create-new-network") {
|
|
if (args.data['new-network-ip'] != null && args.data['new-network-ip'].length > 0) {
|
|
$.extend(ipToNetwork, {
|
|
ip: args.data['new-network-ip']
|
|
});
|
|
}
|
|
} else {
|
|
if (args.data["my-network-ips"][i] != null && args.data["my-network-ips"][i].length > 0) {
|
|
$.extend(ipToNetwork, {
|
|
ip: args.data["my-network-ips"][i]
|
|
});
|
|
}
|
|
}
|
|
array3.unshift(ipToNetwork);
|
|
|
|
} else {
|
|
array2.push(checkedNetworkIdArray[i]);
|
|
|
|
var ipToNetwork = {
|
|
networkid: checkedNetworkIdArray[i]
|
|
};
|
|
if (args.data["my-network-ips"][i] != null && args.data["my-network-ips"][i].length > 0) {
|
|
$.extend(ipToNetwork, {
|
|
ip: args.data["my-network-ips"][i]
|
|
});
|
|
}
|
|
array3.push(ipToNetwork);
|
|
}
|
|
}
|
|
}
|
|
|
|
//deployVmData.push("&networkIds=" + array2.join(",")); //ipToNetworkMap can't be specified along with networkIds or ipAddress
|
|
|
|
for (var k = 0; k < array3.length; k++) {
|
|
deployVmData["iptonetworklist[" + k + "].networkid"] = array3[k].networkid;
|
|
if (array3[k].ip != undefined && array3[k].ip.length > 0) {
|
|
deployVmData["iptonetworklist[" + k + "].ip"] = array3[k].ip;
|
|
}
|
|
}
|
|
|
|
} else if (step6ContainerType == '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) {
|
|
$.extend(deployVmData, {
|
|
securitygroupids : checkedSecurityGroupIdArray.join(",")
|
|
});
|
|
}
|
|
|
|
if (selectedZoneObj.networktype == "Advanced" && selectedZoneObj.securitygroupsenabled == true) { // Advanced SG-enabled zone
|
|
var array2 = [];
|
|
var myNetworks = $('.multi-wizard:visible form').data('my-networks'); //widget limitation: If using an advanced security group zone, get the guest networks like this
|
|
var defaultNetworkId = $('.multi-wizard:visible form').find('input[name=defaultNetwork]:checked').val();
|
|
|
|
var checkedNetworkIdArray;
|
|
if (typeof(myNetworks) == "object" && myNetworks.length != null) { //myNetworks is an array of string, e.g. ["203", "202"],
|
|
checkedNetworkIdArray = myNetworks;
|
|
} else if (typeof(myNetworks) == "string" && myNetworks.length > 0) { //myNetworks is a string, e.g. "202"
|
|
checkedNetworkIdArray = [];
|
|
checkedNetworkIdArray.push(myNetworks);
|
|
} else { // typeof(myNetworks) == null
|
|
checkedNetworkIdArray = [];
|
|
}
|
|
|
|
//add default network first
|
|
if (defaultNetworkId != null && defaultNetworkId.length > 0 && defaultNetworkId != 'new-network') {
|
|
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]);
|
|
}
|
|
}
|
|
|
|
$.extend(deployVmData, {
|
|
networkids : array2.join(",")
|
|
});
|
|
}
|
|
} else if (step6ContainerType == 'nothing-to-select') {
|
|
if ("vpc" in args.context) { //from VPC tier
|
|
deployVmData["iptonetworklist[0].networkid"] = args.context.networks[0].id;
|
|
if (args.data["vpc-specify-ip"] != undefined && args.data["vpc-specify-ip"].length > 0) {
|
|
deployVmData["iptonetworklist[0].ip"] = args.data["vpc-specify-ip"];
|
|
}
|
|
|
|
$.extend(deployVmData, {
|
|
domainid : args.context.vpc[0].domainid
|
|
});
|
|
if (args.context.vpc[0].account != null) {
|
|
$.extend(deployVmData, {
|
|
account : args.context.vpc[0].account
|
|
});
|
|
} else if (args.context.vpc[0].projectid != null) {
|
|
$.extend(deployVmData, {
|
|
projectid : args.context.vpc[0].projectid
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
//step 4: select ssh key pair
|
|
if (args.data.sshkeypair != null && args.data.sshkeypair.length > 0) {
|
|
$.extend(deployVmData, {
|
|
keypair : args.data.sshkeypair
|
|
});
|
|
}
|
|
|
|
var displayname = args.data.displayname;
|
|
if (displayname != null && displayname.length > 0) {
|
|
$.extend(deployVmData, {
|
|
displayname : displayname
|
|
});
|
|
$.extend(deployVmData, {
|
|
name : displayname
|
|
});
|
|
}
|
|
|
|
var group = args.data.groupname;
|
|
if (group != null && group.length > 0) {
|
|
$.extend(deployVmData, {
|
|
group : group
|
|
});
|
|
}
|
|
|
|
var keyboard = args.data.keyboardLanguage;
|
|
if (keyboard != null && keyboard.length > 0) { //when blank option (default option) is selected => args.data.keyboardLanguage == ""
|
|
$.extend(deployVmData, {
|
|
keyboard : keyboard
|
|
});
|
|
}
|
|
|
|
if (g_hostid != null) {
|
|
$.extend(deployVmData, {
|
|
hostid : g_hostid
|
|
});
|
|
}
|
|
|
|
var userdata = args.data.userdata;
|
|
if (userdata != null && userdata.length > 0) {
|
|
|
|
$.extend(deployVmData, {
|
|
userdata : encodeURIComponent(btoa(cloudStack.sanitizeReverse(userdata)))
|
|
});
|
|
}
|
|
|
|
$(window).trigger('cloudStack.deployVirtualMachine', {
|
|
deployVmData: deployVmData,
|
|
formData: args.data
|
|
});
|
|
|
|
$.ajax({
|
|
url: createURL('deployVirtualMachine'),
|
|
data: deployVmData,
|
|
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)
|
|
cloudStack.dialog.notice({
|
|
message: "Password of new VM " + item.displayname + " is " + item.password
|
|
});
|
|
return item;
|
|
},
|
|
getActionFilter: function() {
|
|
return cloudStack.actionFilter.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));
|