cloudstack/ui/scripts/storage.js
Chris Suich 0ed7ebd7e7 Squashed & merged commit of the following:
commit c9ee0d12e191e803fb341f3f96e95ca434a36f6c
Author: Wei Zhou <w.zhou@leaseweb.com>
Date:   Wed Oct 23 16:55:10 2013 +0200

    CLOUDSTACK-4931, CLOUDSTACK-4937: setDetails to user VMs only
    (cherry picked from commit a94acc5a43aeaf5f18f1912e2653a92f6041a6e5)

commit fe1586c71377bc6d219db2dcf088c40b65dd1fc4
Author: Anthony Xu <anthony.xu@citrix.com>
Date:   Tue Oct 22 11:20:27 2013 -0700

    CLOUDSTACK-4649:
            vm sync tracks the pv driver version for xenserver

     Anthony

commit 56a218f66eda540b4b4b04030ee71fc6863f8532
Author: Anthony Xu <anthony.xu@citrix.com>
Date:   Mon Oct 21 16:10:07 2013 -0700

    CLOUDSTACK-4649:
        xs 6.1/6.2 introduce the new virtual platform, so there are two virtual platforms, windows PV driver version must match virtual platforms,
    this patch tracks PV driver versions in vm details and template details.

    Anthony

commit 4e85d28c678a6f96b5b70d8d33fc60f9d1ea3df6
Author: Laszlo Hornyak <laszlo.hornyak@gmail.com>
Date:   Mon Oct 21 21:17:33 2013 +0200

    removed unused static field

    - s_httpClientManager was not used

    Signed-off-by: Laszlo Hornyak <laszlo.hornyak@gmail.com>

commit d4121fa26023db236f7396cea455ef090672ae9a
Author: Chris Suich <chris.suich@netapp.com>
Date:   Tue Oct 22 10:45:22 2013 -0400

    Updated DataMotionServiceImpl and ApiResponseHelper based on review feedback.

commit aaf026e1e4204d405bcda2ae4f1a01b1d0f7e7cb
Author: Chris Suich <chris.suich@netapp.com>
Date:   Thu Oct 17 14:27:12 2013 -0400

    Added context to strategy sorting error responses
    Added TODOs for DRYing out pickStrategy() overloading

commit a221f4aa3fb2ddc255bc35cf753f98f88f5bf44e
Author: Chris Suich <chris.suich@netapp.com>
Date:   Wed Oct 16 09:57:28 2013 -0400

    Updated inefficient strategy sorting/selection
    Removed unnecessary canRevertSnapshot from PrimaryDataStoreDriver
    Other general cleaup and fixes from reviews

commit 7d58949c6a1b7e853e891b59387a9620e8cd7a91
Author: Chris Suich <chris.suich@netapp.com>
Date:   Mon Oct 14 14:01:22 2013 -0400

    Added volume snapshot revert capability to SnapshotResponse
    Updated UI to hide/show snapshot revert action per snapshot

Signed-off-by: Edison Su <sudison@gmail.com>
2013-10-23 12:21:43 -07:00

1973 lines
106 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 diskofferingObjs, selectedDiskOfferingObj;
cloudStack.sections.storage = {
title: 'label.storage',
id: 'storage',
sectionSelect: {
label: 'label.select-view'
},
sections: {
/**
* Volumes
*/
volumes: {
type: 'select',
title: 'label.volumes',
listView: {
id: 'volumes',
label: 'label.volumes',
preFilter: function(args) {
var hiddenFields = [];
if (isAdmin() != true)
hiddenFields.push('hypervisor');
return hiddenFields;
},
fields: {
name: {
label: 'label.name'
},
type: {
label: 'label.type'
},
hypervisor: {
label: 'label.hypervisor'
},
vmdisplayname: {
label: 'label.vm.display.name'
}
/*
state: {
label: 'State',
indicator: {
'Ready': 'on'
}
}
*/
},
// List view actions
actions: {
// Add volume
add: {
label: 'label.add.volume',
messages: {
confirm: function(args) {
return 'message.add.volume';
},
notification: function(args) {
return 'label.add.volume';
}
},
createForm: {
title: 'label.add.volume',
desc: 'message.add.volume',
fields: {
name: {
docID: 'helpVolumeName',
label: 'label.name',
validation: {
required: true
}
},
availabilityZone: {
label: 'label.availability.zone',
docID: 'helpVolumeAvailabilityZone',
select: function(args) {
$.ajax({
url: createURL("listZones&available=true"),
dataType: "json",
async: true,
success: function(json) {
var zoneObjs = json.listzonesresponse.zone;
args.response.success({
descriptionField: 'name',
data: zoneObjs
});
}
});
}
},
diskOffering: {
label: 'label.disk.offering',
docID: 'helpVolumeDiskOffering',
select: function(args) {
$.ajax({
url: createURL("listDiskOfferings"),
dataType: "json",
async: false,
success: function(json) {
diskofferingObjs = json.listdiskofferingsresponse.diskoffering;
var items = [];
$(diskofferingObjs).each(function() {
items.push({
id: this.id,
description: this.displaytext
});
});
args.response.success({
data: items
});
}
});
args.$select.change(function() {
var diskOfferingId = $(this).val();
$(diskofferingObjs).each(function() {
if (this.id == diskOfferingId) {
selectedDiskOfferingObj = this;
return false; //break the $.each() loop
}
});
if (selectedDiskOfferingObj == null)
return;
var $form = $(this).closest('form');
var $diskSize = $form.find('.form-item[rel=diskSize]');
if (selectedDiskOfferingObj.iscustomized == true) {
$diskSize.css('display', 'inline-block');
} else {
$diskSize.hide();
}
var $minIops = $form.find('.form-item[rel=minIops]');
var $maxIops = $form.find('.form-item[rel=maxIops]');
if (selectedDiskOfferingObj.iscustomizediops == true) {
$minIops.css('display', 'inline-block');
$maxIops.css('display', 'inline-block');
} else {
$minIops.hide();
$maxIops.hide();
}
});
}
}
,
diskSize: {
label: 'label.disk.size.gb',
validation: {
required: true,
number: true
},
isHidden: true
},
minIops: {
label: 'label.disk.iops.min',
validation: {
required: false,
number: true
},
isHidden: true
},
maxIops: {
label: 'label.disk.iops.max',
validation: {
required: false,
number: true
},
isHidden: true
}
}
},
action: function(args) {
var data = {
name: args.data.name,
zoneId: args.data.availabilityZone,
diskOfferingId: args.data.diskOffering
};
// if(thisDialog.find("#size_container").css("display") != "none") { //wait for Brian to include $form in args
if (selectedDiskOfferingObj.iscustomized == true) {
$.extend(data, {
size: args.data.diskSize
});
}
if (selectedDiskOfferingObj.iscustomizediops == true) {
if (args.data.minIops != "" && args.data.minIops > 0) {
$.extend(data, {
miniops: args.data.minIops
});
}
if (args.data.maxIops != "" && args.data.maxIops > 0) {
$.extend(data, {
maxiops: args.data.maxIops
});
}
}
$.ajax({
url: createURL('createVolume'),
data: data,
success: function(json) {
var jid = json.createvolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.volume;
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
},
error: function(json) {
args.response.error(parseXMLHttpResponse(json));
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
uploadVolume: {
isHeader: true,
label: 'label.upload.volume',
messages: {
notification: function() {
return 'label.upload.volume';
}
},
createForm: {
title: 'label.upload.volume',
fields: {
name: {
label: 'label.name',
validation: {
required: true
},
docID: 'helpUploadVolumeName'
},
availabilityZone: {
label: 'label.availability.zone',
docID: 'helpUploadVolumeZone',
select: function(args) {
$.ajax({
url: createURL("listZones&available=true"),
dataType: "json",
async: true,
success: function(json) {
var zoneObjs = json.listzonesresponse.zone;
args.response.success({
descriptionField: 'name',
data: zoneObjs
});
}
});
}
},
format: {
label: 'label.format',
docID: 'helpUploadVolumeFormat',
select: function(args) {
var items = [];
items.push({
id: 'RAW',
description: 'RAW'
});
items.push({
id: 'VHD',
description: 'VHD'
});
items.push({
id: 'OVA',
description: 'OVA'
});
items.push({
id: 'QCOW2',
description: 'QCOW2'
});
args.response.success({
data: items
});
}
},
url: {
label: 'label.url',
docID: 'helpUploadVolumeURL',
validation: {
required: true
}
},
checksum: {
docID: 'helpUploadVolumeChecksum',
label: 'label.checksum'
}
}
},
action: function(args) {
var data = {
name: args.data.name,
zoneId: args.data.availabilityZone,
format: args.data.format,
url: args.data.url
};
if (args.data.checksum != null && args.data.checksum.length > 0) {
$.extend(data, {
checksum: args.data.checksum
});
}
$.ajax({
url: createURL('uploadVolume'),
data: data,
success: function(json) {
var jid = json.uploadvolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.volume;
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
},
error: function(json) {
args.response.error(parseXMLHttpResponse(json));
}
});
},
notification: {
poll: pollAsyncJobResult
}
}
},
advSearchFields: {
name: {
label: 'Name'
},
zoneid: {
label: 'Zone',
select: function(args) {
$.ajax({
url: createURL('listZones'),
data: {
listAll: true
},
success: function(json) {
var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone : [];
args.response.success({
data: $.map(zones, function(zone) {
return {
id: zone.id,
description: zone.name
};
})
});
}
});
}
},
domainid: {
label: 'Domain',
select: function(args) {
if (isAdmin() || isDomainAdmin()) {
$.ajax({
url: createURL('listDomains'),
data: {
listAll: true,
details: 'min'
},
success: function(json) {
var array1 = [{
id: '',
description: ''
}];
var domains = json.listdomainsresponse.domain;
if (domains != null && domains.length > 0) {
for (var i = 0; i < domains.length; i++) {
array1.push({
id: domains[i].id,
description: domains[i].path
});
}
}
args.response.success({
data: array1
});
}
});
} else {
args.response.success({
data: null
});
}
},
isHidden: function(args) {
if (isAdmin() || isDomainAdmin())
return false;
else
return true;
}
},
account: {
label: 'Account',
isHidden: function(args) {
if (isAdmin() || isDomainAdmin())
return false;
else
return true;
}
},
tagKey: {
label: 'Tag Key'
},
tagValue: {
label: 'Tag Value'
}
},
dataProvider: function(args) {
var data = {};
listViewDataProvider(args, data);
if (args.context != null) {
if ("instances" in args.context) {
$.extend(data, {
virtualMachineId: args.context.instances[0].id
});
}
}
$.ajax({
url: createURL('listVolumes'),
data: data,
success: function(json) {
var items = json.listvolumesresponse.volume;
args.response.success({
actionFilter: volumeActionfilter,
data: items
});
}
});
},
detailView: {
name: 'Volume details',
viewAll: {
path: 'storage.snapshots',
label: 'label.snapshots'
},
actions: {
migrateVolume: {
label: 'Migrate Volume',
messages: {
confirm: function(args) {
return 'Do you want to migrate this volume ?';
},
notification: function(args) {
return 'Volume migrated';
}
},
createForm: {
title: 'Migrate Volume',
desc: '',
fields: {
storagePool: {
label: 'Storage Pool',
validation: {
required: true
},
select: function(args) {
$.ajax({
url: createURL("findStoragePoolsForMigration&id=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
var pools = json.findstoragepoolsformigrationresponse.storagepool;
var items = [];
$(pools).each(function() {
items.push({
id: this.id,
description: this.name + " (" + (this.suitableformigration ? "Suitable" : "Not Suitable") + ")"
});
});
args.response.success({
data: items
});
}
});
}
}
}
},
action: function(args) {
$.ajax({
url: createURL("migrateVolume&livemigrate=true&storageid=" + args.data.storagePool + "&volumeid=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
var jid = json.migratevolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
takeSnapshot: {
label: 'label.action.take.snapshot',
messages: {
confirm: function(args) {
return 'message.action.take.snapshot';
},
notification: function(args) {
return 'label.action.take.snapshot';
}
},
action: function(args) {
$.ajax({
url: createURL("createSnapshot&volumeid=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
var jid = json.createsnapshotresponse.jobid;
args.response.success({
_custom: {
jobId: jid //take snapshot from a volume doesn't change any property in this volume. So, don't need to specify getUpdatedItem() to return updated volume. Besides, createSnapshot API doesn't return updated volume.
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
recurringSnapshot: {
label: 'label.snapshot.schedule',
action: {
custom: cloudStack.uiCustom.recurringSnapshots({
desc: 'message.snapshot.schedule',
dataProvider: function(args) {
$.ajax({
url: createURL('listSnapshotPolicies'),
data: {
volumeid: args.context.volumes[0].id
},
async: true,
dataType: 'json',
success: function(data) {
args.response.success({
data: $.map(
data.listsnapshotpoliciesresponse.snapshotpolicy ? data.listsnapshotpoliciesresponse.snapshotpolicy : [],
function(snapshot, index) {
return {
id: snapshot.id,
type: snapshot.intervaltype,
time: snapshot.intervaltype > 0 ? snapshot.schedule.split(':')[1] + ':' + snapshot.schedule.split(':')[0] : snapshot.schedule,
timezone: snapshot.timezone,
keep: snapshot.maxsnaps,
'day-of-week': snapshot.intervaltype == 2 ? snapshot.schedule.split(':')[2] : null,
'day-of-month': snapshot.intervaltype == 3 ? snapshot.schedule.split(':')[2] : null
};
}
)
});
}
});
},
actions: {
add: function(args) {
var snap = args.snapshot;
var data = {
keep: snap.maxsnaps,
timezone: snap.timezone
};
var convertTime = function(minute, hour, meridiem, extra) {
var convertedHour = meridiem == 'PM' ?
(hour != 12 ? parseInt(hour) + 12 : 12) : (hour != 12 ? hour : '00');
var time = minute + ':' + convertedHour;
if (extra) time += ':' + extra;
return time;
};
switch (snap['snapshot-type']) {
case 'hourly': // Hourly
$.extend(data, {
schedule: snap.schedule
});
break;
case 'daily': // Daily
$.extend(data, {
schedule: convertTime(
snap['time-minute'],
snap['time-hour'],
snap['time-meridiem']
)
});
break;
case 'weekly': // Weekly
$.extend(data, {
schedule: convertTime(
snap['time-minute'],
snap['time-hour'],
snap['time-meridiem'],
snap['day-of-week']
)
});
break;
case 'monthly': // Monthly
$.extend(data, {
schedule: convertTime(
snap['time-minute'],
snap['time-hour'],
snap['time-meridiem'],
snap['day-of-month']
)
});
break;
}
$.ajax({
url: createURL('createSnapshotPolicy'),
data: {
volumeid: args.context.volumes[0].id,
intervaltype: snap['snapshot-type'],
maxsnaps: snap.maxsnaps,
schedule: data.schedule,
timezone: snap.timezone
},
dataType: 'json',
async: true,
success: function(successData) {
var snapshot = successData.createsnapshotpolicyresponse.snapshotpolicy;
args.response.success({
data: {
id: snapshot.id,
type: snapshot.intervaltype,
time: snapshot.intervaltype > 0 ? snapshot.schedule.split(':')[1] + ':' + snapshot.schedule.split(':')[0] : snapshot.schedule,
timezone: snapshot.timezone,
keep: snapshot.maxsnaps,
'day-of-week': snapshot.intervaltype == 2 ? snapshot.schedule.split(':')[2] : null,
'day-of-month': snapshot.intervaltype == 3 ? snapshot.schedule.split(':')[2] : null
}
});
}
});
},
remove: function(args) {
$.ajax({
url: createURL('deleteSnapshotPolicies'),
data: {
id: args.snapshot.id
},
dataType: 'json',
async: true,
success: function(data) {
args.response.success();
}
});
}
},
// Select data
selects: {
schedule: function(args) {
var time = [];
for (var i = 1; i <= 59; i++) {
time.push({
id: i,
name: i
});
}
args.response.success({
data: time
});
},
timezone: function(args) {
args.response.success({
data: $.map(timezoneMap, function(value, key) {
return {
id: key,
name: value
};
})
});
},
'day-of-week': function(args) {
args.response.success({
data: [{
id: 1,
name: 'label.sunday'
}, {
id: 2,
name: 'label.monday'
}, {
id: 3,
name: 'label.tuesday'
}, {
id: 4,
name: 'label.wednesday'
}, {
id: 5,
name: 'label.thursday'
}, {
id: 6,
name: 'label.friday'
}, {
id: 7,
name: 'label.saturday'
}]
});
},
'day-of-month': function(args) {
var time = [];
for (var i = 1; i <= 31; i++) {
time.push({
id: i,
name: i
});
}
args.response.success({
data: time
});
},
'time-hour': function(args) {
var time = [];
for (var i = 1; i <= 12; i++) {
time.push({
id: i,
name: i
});
}
args.response.success({
data: time
});
},
'time-minute': function(args) {
var time = [];
for (var i = 0; i <= 59; i++) {
time.push({
id: i < 10 ? '0' + i : i,
name: i < 10 ? '0' + i : i
});
}
args.response.success({
data: time
});
},
'time-meridiem': function(args) {
args.response.success({
data: [{
id: 'AM',
name: 'AM'
}, {
id: 'PM',
name: 'PM'
}]
});
}
}
})
},
messages: {
notification: function(args) {
return 'label.snapshot.schedule';
}
}
},
attachDisk: {
addRow: 'false',
label: 'label.action.attach.disk',
messages: {
confirm: function(args) {
return 'Are you sure you want to attach disk?';
},
notification: function(args) {
return 'label.action.attach.disk';
}
},
createForm: {
title: 'label.action.attach.disk',
desc: 'label.action.attach.disk',
fields: {
virtualMachineId: {
label: 'label.instance',
select: function(args) {
var zoneid = args.context.volumes[0].zoneid;
var items = [];
var data;
if (!args.context.projects) {
data = {
zoneid: zoneid,
domainid: args.context.volumes[0].domainid,
account: args.context.volumes[0].account
};
} else {
data = {
zoneid: zoneid,
projectid: args.context.projects[0].id
};
}
if (args.context.volumes[0].hypervisor != null && args.context.volumes[0].hypervisor.length > 0 && args.context.volumes[0].hypervisor != 'None') {
data = $.extend(data, {
hypervisor: args.context.volumes[0].hypervisor
});
}
$(['Running', 'Stopped']).each(function() {
$.ajax({
url: createURL('listVirtualMachines'),
data: $.extend(data, {
state: this.toString()
}),
async: false,
success: function(json) {
var instanceObjs = json.listvirtualmachinesresponse.virtualmachine;
$(instanceObjs).each(function() {
items.push({
id: this.id,
description: this.displayname ? this.displayname : this.name
});
});
}
});
});
args.response.success({
data: items
});
}
}
}
},
action: function(args) {
$.ajax({
url: createURL("attachVolume&id=" + args.context.volumes[0].id + '&virtualMachineId=' + args.data.virtualMachineId),
dataType: "json",
async: true,
success: function(json) {
var jid = json.attachvolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.volume;
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
detachDisk: {
label: 'label.action.detach.disk',
messages: {
confirm: function(args) {
return 'message.detach.disk';
},
notification: function(args) {
return 'label.action.detach.disk';
}
},
action: function(args) {
$.ajax({
url: createURL("detachVolume&id=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
var jid = json.detachvolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return {
virtualmachineid: null,
vmname: null
};
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
downloadVolume: {
label: 'label.action.download.volume',
messages: {
confirm: function(args) {
return 'message.download.volume.confirm';
},
notification: function(args) {
return 'label.action.download.volume';
},
complete: function(args) {
var url = args.url;
var htmlMsg = _l('message.download.volume');
var htmlMsg2 = htmlMsg.replace(/#/, url).replace(/00000/, url);
//$infoContainer.find("#info").html(htmlMsg2);
return htmlMsg2;
}
},
action: function(args) {
$.ajax({
url: createURL("extractVolume&id=" + args.context.volumes[0].id + "&zoneid=" + args.context.volumes[0].zoneid + "&mode=HTTP_DOWNLOAD"),
dataType: "json",
async: true,
success: function(json) {
var jid = json.extractvolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.volume;
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
createTemplate: {
label: 'label.create.template',
messages: {
confirm: function(args) {
return 'message.create.template';
},
notification: function(args) {
return 'label.create.template';
}
},
createForm: {
title: 'label.create.template',
preFilter: cloudStack.preFilter.createTemplate,
desc: '',
fields: {
name: {
label: 'label.name',
validation: {
required: true
}
},
displayText: {
label: 'label.description',
validation: {
required: true
}
},
osTypeId: {
label: 'label.os.type',
select: function(args) {
$.ajax({
url: createURL("listOsTypes"),
dataType: "json",
async: true,
success: function(json) {
var ostypes = json.listostypesresponse.ostype;
var items = [];
$(ostypes).each(function() {
items.push({
id: this.id,
description: this.description
});
});
args.response.success({
data: items
});
}
});
}
},
isPublic: {
label: 'label.public',
isBoolean: true
},
isPasswordEnabled: {
label: 'label.password.enabled',
isBoolean: true
},
isFeatured: {
label: "label.featured",
isBoolean: true
},
isdynamicallyscalable: {
label: "Dynamically Scalable",
isBoolean: true
}
}
},
action: function(args) {
var data = {
volumeId: args.context.volumes[0].id,
name: args.data.name,
displayText: args.data.displayText,
osTypeId: args.data.osTypeId,
isPublic: (args.data.isPublic == "on"),
passwordEnabled: (args.data.isPasswordEnabled == "on"),
isdynamicallyscalable: (args.data.isdynamicallyscalable == "on")
};
if (args.$form.find('.form-item[rel=isFeatured]').css("display") != "none") {
$.extend(data, {
isfeatured: (args.data.isFeatured == "on")
});
}
$.ajax({
url: createURL('createTemplate'),
data: data,
success: function(json) {
var jid = json.createtemplateresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return {}; //no properties in this volume needs to be updated
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
migrateToAnotherStorage: {
label: 'label.migrate.volume',
messages: {
confirm: function(args) {
return 'message.migrate.volume';
},
notification: function(args) {
return 'label.migrate.volume';
}
},
createForm: {
title: 'label.migrate.volume',
desc: '',
fields: {
storageId: {
label: 'label.primary.storage',
validation: {
required: true
},
select: function(args) {
$.ajax({
url: createURL("listStoragePools&zoneid=" + args.context.volumes[0].zoneid),
dataType: "json",
async: true,
success: function(json) {
var pools = json.liststoragepoolsresponse.storagepool;
var items = [];
$(pools).each(function() {
items.push({
id: this.id,
description: this.name
});
});
args.response.success({
data: items
});
}
});
}
}
}
},
action: function(args) {
$.ajax({
url: createURL("migrateVolume&storageid=" + args.data.storageId + "&volumeid=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
var jid = json.migratevolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.volume;
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
remove: {
label: 'label.action.delete.volume',
messages: {
confirm: function(args) {
return 'message.action.delete.volume';
},
notification: function(args) {
return 'label.action.delete.volume';
}
},
action: function(args) {
$.ajax({
url: createURL("deleteVolume&id=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
args.response.success();
}
});
},
notification: {
poll: function(args) {
args.complete();
}
}
},
resize: {
label: 'label.action.resize.volume',
messages: {
notification: function(args) {
return 'label.action.resize.volume';
}
},
createForm: {
title: 'label.action.resize.volume',
fields: {
newdiskoffering: {
label: 'label.resize.new.offering.id',
select: function(args) {
$.ajax({
url: createURL("listDiskOfferings"),
dataType: "json",
async: false,
success: function(json) {
diskofferingObjs = json.listdiskofferingsresponse.diskoffering;
var items = [];
$(diskofferingObjs).each(function() {
items.push({
id: this.id,
description: this.displaytext
});
});
args.response.success({
data: items
});
}
});
args.$select.change(function() {
var diskOfferingId = $(this).val();
$(diskofferingObjs).each(function() {
if (this.id == diskOfferingId) {
selectedDiskOfferingObj = this;
return false; //break the $.each() loop
}
});
if (selectedDiskOfferingObj == null)
return;
var $form = $(this).closest('form');
var $newsize = $form.find('.form-item[rel=newsize]');
if (selectedDiskOfferingObj.iscustomized == true) {
$newsize.css('display', 'inline-block');
} else {
$newsize.hide();
}
});
}
},
newsize: {
label: 'label.resize.new.size',
validation: {
required: true,
number: true
},
isHidden: true
},
shrinkok: {
label: 'label.resize.shrink.ok',
isBoolean: true,
isChecked: false
}
}
},
action: function(args) {
var array1 = [];
array1.push("&shrinkok=" + (args.data.shrinkok == "on"));
var newDiskOffering = args.data.newdiskoffering;
var newSize;
if (selectedDiskOfferingObj.iscustomized == true) {
newSize = args.data.newsize;
}
if (newDiskOffering != null && newDiskOffering.length > 0) {
array1.push("&diskofferingid=" + todb(newDiskOffering));
}
if (newSize != null && newSize.length > 0) {
array1.push("&size=" + todb(newSize));
}
$.ajax({
url: createURL("resizeVolume&id=" + args.context.volumes[0].id + array1.join("")),
dataType: "json",
async: true,
success: function(json) {
var jid = json.resizevolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return json.queryasyncjobresultresponse.jobresult.volume;
},
getActionFilter: function() {
return volumeActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
}
},
tabs: {
details: {
title: 'label.details',
preFilter: function(args) {
var hiddenFields;
if (isAdmin()) {
hiddenFields = [];
} else {
hiddenFields = ['storage', 'hypervisor'];
}
return hiddenFields;
},
fields: [{
name: {
label: 'label.name',
isEditable: true
}
}, {
id: {
label: 'ID'
},
zonename: {
label: 'label.zone'
},
state: {
label: 'label.state',
pollAgainIfValueIsIn: {
'UploadNotStarted': 1
},
pollAgainFn: function(context) {
var toClearInterval = false;
$.ajax({
url: createURL("listVolumes&id=" + context.volumes[0].id),
dataType: "json",
async: false,
success: function(json) {
var jsonObj = json.listvolumesresponse.volume[0];
if (jsonObj.state != context.volumes[0].state) {
toClearInterval = true; //to clear interval
}
}
});
return toClearInterval;
}
},
status: {
label: 'label.status'
},
type: {
label: 'label.type'
},
storagetype: {
label: 'label.storage.type'
},
hypervisor: {
label: 'label.hypervisor'
},
size: {
label: 'Size ',
converter: function(args) {
if (args == null || args == 0)
return "";
else
return cloudStack.converters.convertBytes(args);
}
},
miniops: {
label: 'label.disk.iops.min',
converter: function(args) {
if (args == null || args == 0)
return "";
else
return args;
}
},
maxiops: {
label: 'label.disk.iops.max',
converter: function(args) {
if (args == null || args == 0)
return "";
else
return args;
}
},
virtualmachineid: {
label: 'VM ID',
converter: function(args) {
if (args == null)
return "detached";
else
return args;
}
},
//vmname: { label: 'label.vm.name' },
vmdisplayname: {
label: 'label.vm.display.name'
},
vmstate: {
label: 'label.vm.state'
},
deviceid: {
label: 'label.device.id'
},
storage: {
label: 'label.storage'
},
created: {
label: 'label.created',
converter: cloudStack.converters.toLocalDate
},
domain: {
label: 'label.domain'
},
account: {
label: 'label.account'
}
}],
tags: cloudStack.api.tags({
resourceType: 'Volume',
contextId: 'volumes'
}),
dataProvider: function(args) {
$.ajax({
url: createURL("listVolumes&id=" + args.context.volumes[0].id),
dataType: "json",
async: true,
success: function(json) {
var jsonObj = json.listvolumesresponse.volume[0];
args.response.success({
actionFilter: volumeActionfilter,
data: jsonObj
});
}
});
}
}
}
}
}
},
/**
* Snapshots
*/
snapshots: {
type: 'select',
title: 'label.snapshots',
listView: {
id: 'snapshots',
label: 'label.snapshots',
fields: {
volumename: {
label: 'label.volume'
},
intervaltype: {
label: 'label.interval.type'
},
created: {
label: 'label.created',
converter: cloudStack.converters.toLocalDate
},
state: {
label: 'label.state',
indicator: {
'BackedUp': 'on',
'Destroyed': 'off'
}
}
},
advSearchFields: {
name: {
label: 'Name'
},
domainid: {
label: 'Domain',
select: function(args) {
if (isAdmin() || isDomainAdmin()) {
$.ajax({
url: createURL('listDomains'),
data: {
listAll: true,
details: 'min'
},
success: function(json) {
var array1 = [{
id: '',
description: ''
}];
var domains = json.listdomainsresponse.domain;
if (domains != null && domains.length > 0) {
for (var i = 0; i < domains.length; i++) {
array1.push({
id: domains[i].id,
description: domains[i].path
});
}
}
args.response.success({
data: array1
});
}
});
} else {
args.response.success({
data: null
});
}
},
isHidden: function(args) {
if (isAdmin() || isDomainAdmin())
return false;
else
return true;
}
},
account: {
label: 'Account',
isHidden: function(args) {
if (isAdmin() || isDomainAdmin())
return false;
else
return true;
}
},
tagKey: {
label: 'Tag Key'
},
tagValue: {
label: 'Tag Value'
}
},
dataProvider: function(args) {
var data = {};
var instanceVolumeIds = [];
listViewDataProvider(args, data);
if (args.context != null) {
if ("volumes" in args.context) {
$.extend(data, {
volumeid: args.context.volumes[0].id
});
} else if (args.context.instances) {
$.ajax({
url: createURL('listVolumes'),
data: {
virtualmachineid: args.context.instances[0].id,
listAll: true
},
async: false,
success: function(json) {
instanceVolumeIds = $.map(json.listvolumesresponse.volume, function(volume) {
return volume.id;
})
}
});
data.volumeid = instanceVolumeIds.join(',');
}
}
$.ajax({
url: createURL('listSnapshots'),
data: data,
success: function(json) {
var items = json.listsnapshotsresponse.snapshot;
args.response.success({
actionFilter: snapshotActionfilter,
data: items
});
}
});
},
detailView: {
name: 'Snapshot detail',
actions: {
createTemplate: {
label: 'label.create.template',
messages: {
confirm: function(args) {
return 'message.create.template';
},
notification: function(args) {
return 'label.create.template';
}
},
createForm: {
title: 'label.create.template',
desc: '',
fields: {
name: {
label: 'label.name',
validation: {
required: true
}
},
displayText: {
label: 'label.description',
validation: {
required: true
}
},
osTypeId: {
label: 'label.os.type',
select: function(args) {
$.ajax({
url: createURL("listOsTypes"),
dataType: "json",
async: true,
success: function(json) {
var ostypes = json.listostypesresponse.ostype;
var items = [];
$(ostypes).each(function() {
items.push({
id: this.id,
description: this.description
});
});
args.response.success({
data: items
});
}
});
}
},
isPublic: {
label: 'label.public',
isBoolean: true
},
isPasswordEnabled: {
label: 'label.password.enabled',
isBoolean: true
},
isdynamicallyscalable: {
label: "Dynamically Scalable",
isBoolean: true
}
}
},
action: function(args) {
var data = {
snapshotid: args.context.snapshots[0].id,
name: args.data.name,
displayText: args.data.displayText,
osTypeId: args.data.osTypeId,
isPublic: (args.data.isPublic == "on"),
passwordEnabled: (args.data.isPasswordEnabled == "on"),
isdynamicallyscalable: (args.data.isdynamicallyscalable == "on")
};
$.ajax({
url: createURL('createTemplate'),
data: data,
success: function(json) {
var jid = json.createtemplateresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return {}; //nothing in this snapshot needs to be updated
},
getActionFilter: function() {
return snapshotActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
createVolume: {
label: 'label.action.create.volume',
messages: {
confirm: function(args) {
return 'Are you sure you want to create volume?';
},
notification: function(args) {
return 'label.action.create.volume';
}
},
createForm: {
title: 'label.action.create.volume',
desc: '',
fields: {
name: {
label: 'label.name',
validation: {
required: true
}
}
}
},
action: function(args) {
var data = {
snapshotid: args.context.snapshots[0].id,
name: args.data.name
};
$.ajax({
url: createURL('createVolume'),
data: data,
success: function(json) {
var jid = json.createvolumeresponse.jobid;
args.response.success({
_custom: {
jobId: jid,
getUpdatedItem: function(json) {
return {}; //nothing in this snapshot needs to be updated
},
getActionFilter: function() {
return snapshotActionfilter;
}
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
revertSnapshot: {
label: 'label.action.revert.snapshot',
messages: {
confirm: function(args) {
return 'message.action.revert.snapshot';
},
notification: function(args) {
return 'label.action.revert.snapshot';
}
},
action: function(args) {
$.ajax({
url: createURL("revertSnapshot&id="+args.context.snapshots[0].id),
dataType: "json",
async: true,
success: function(json) {
var jid = json.revertsnapshotresponse.jobid;
args.response.success({
_custom: {
jobId: jid
}
});
}
});
},
notification: {
poll: pollAsyncJobResult
}
},
remove: {
label: 'label.action.delete.snapshot',
messages: {
confirm: function(args) {
return 'message.action.delete.snapshot';
},
notification: function(args) {
return 'label.action.delete.snapshot';
}
},
action: function(args) {
$.ajax({
url: createURL("deleteSnapshot&id=" + args.context.snapshots[0].id),
dataType: "json",
async: true,
success: function(json) {
var jid = json.deletesnapshotresponse.jobid;
args.response.success({
_custom: {
jobId: jid
}
});
}
});
},
notification: {
poll: function(args) {
args.complete();
}
}
}
},
tabs: {
details: {
title: 'label.details',
fields: [{
name: {
label: 'label.name'
}
}, {
id: {
label: 'label.id'
},
volumename: {
label: 'label.volume.name'
},
state: {
label: 'label.state'
},
intervaltype: {
label: 'label.interval.type'
},
domain: {
label: 'label.domain'
},
account: {
label: 'label.account'
},
created: {
label: 'label.created',
converter: cloudStack.converters.toLocalDate
}
}],
tags: cloudStack.api.tags({
resourceType: 'Snapshot',
contextId: 'snapshots'
}),
dataProvider: function(args) {
$.ajax({
url: createURL("listSnapshots&id=" + args.context.snapshots[0].id),
dataType: "json",
async: true,
success: function(json) {
var jsonObj = json.listsnapshotsresponse.snapshot[0];
args.response.success({
actionFilter: snapshotActionfilter,
data: jsonObj
});
}
});
}
}
}
}
}
}
}
};
var volumeActionfilter = function(args) {
var jsonObj = args.context.item;
var allowedActions = [];
if (jsonObj.state == 'Destroyed' || jsonObj.state == 'Migrating' || jsonObj.state == 'Uploading') {
return [];
}
if (jsonObj.state == 'UploadError') {
return ["remove"];
}
if (jsonObj.hypervisor != "Ovm" && jsonObj.state == "Ready") {
if (jsonObj.hypervisor == 'KVM') {
if (g_KVMsnapshotenabled == true) {
allowedActions.push("takeSnapshot");
allowedActions.push("recurringSnapshot");
} else {
if(jsonObj.vmstate == 'Stopped') {
allowedActions.push("takeSnapshot");
}
}
} else {
allowedActions.push("takeSnapshot");
allowedActions.push("recurringSnapshot");
}
if (jsonObj.type == "DATADISK") {
allowedActions.push("resize");
}
}
if (jsonObj.state != "Allocated") {
if ((jsonObj.vmstate == "Stopped" || jsonObj.virtualmachineid == null) && jsonObj.state == "Ready") {
allowedActions.push("downloadVolume");
}
}
if (jsonObj.type == "ROOT" || jsonObj.type == "DATADISK") {
if (jsonObj.state == "Ready" && isAdmin() && jsonObj.virtualmachineid != null) {
allowedActions.push("migrateVolume");
}
}
if (jsonObj.state != "Creating") {
if (jsonObj.type == "ROOT") {
if (jsonObj.vmstate == "Stopped") {
allowedActions.push("createTemplate");
}
} else { //jsonObj.type == "DATADISK"
if (jsonObj.virtualmachineid != null) {
if (jsonObj.vmstate == "Running" || jsonObj.vmstate == "Stopped" || jsonObj.vmstate == "Destroyed") {
allowedActions.push("detachDisk");
}
} else { // Disk not attached
allowedActions.push("remove");
if (jsonObj.state == "Ready" && isAdmin() && jsonObj.storagetype == "shared") {
allowedActions.push("migrateToAnotherStorage");
}
allowedActions.push("attachDisk");
}
}
}
return allowedActions;
};
var snapshotActionfilter = function(args) {
var jsonObj = args.context.item;
if (jsonObj.state == 'Destroyed') {
return [];
}
var allowedActions = [];
if (jsonObj.state == "BackedUp") {
allowedActions.push("createTemplate");
allowedActions.push("createVolume");
if (jsonObj.revertable && args.context.volumes[0].vmstate == "Stopped") {
allowedActions.push("revertSnapshot");
}
}
allowedActions.push("remove");
return allowedActions;
}
})(cloudStack);