1 function formUpdater(url_choices, url_options, url_defaults){
2 /* Live form updating for the create VM template */
7 var cluster = $("#id_cluster");
8 var owner = $("#id_owner");
9 var snode = $("#id_snode").parent("p");
10 var pnode = $("#id_pnode").parent("p");
11 var hypervisor = $("#id_hypervisor");
12 var disk_type = $("#id_disk_type");
13 var disks = $("#disks");
14 var disk_count = $("#id_disk_count");
15 var disk_add = $("#disks .add");
16 var disk_delete = $("#disks .delete");
17 var nics = $("#nics");
18 var nic_count = $("#id_nic_count");
19 var nic_add = $("#nics .add");
20 var nic_delete = $("#nics .delete");
21 var nic_type = $("#id_nic_type");
22 var nic_link = $("#nics input[name^=nic_link]");
23 var disk_template = $("#id_disk_template");
24 var nic_mode = $("#nics select[name^=nic_mode]");
25 var iallocator = $("#id_iallocator");
26 var iallocator_hostname = $("#id_iallocator_hostname");
27 var boot_order = $("#id_boot_order");
28 var image_path = $("#id_cdrom_image_path").parent("p");
29 var image2_path = $("#id_cdrom2_image_path").parent("p");
30 var root_path = $("#id_root_path");
31 var kernel_path = $("#id_kernel_path");
32 var serial_console = $("#id_serial_console").parent("p");
33 var no_install = $("#id_no_install");
34 var start = $("#id_start").parent("p");
35 var using_str = " Using: ";
36 var blankOptStr = "---------";
37 var nodes = null; // nodes available
39 var template_choices = $("\
40 <option value=''>---------</option>\
41 <option value='plain'>plain</option>\
42 <option value='drbd'>drbd</option>\
43 <option value='file'>file</option>\
44 <option value='diskless'>diskless</option>\
47 var single_node_template_choices = $("\
48 <option value=''>---------</option>\
49 <option value='plain'>plain</option>\
50 <option value='file'>file</option>\
51 <option value='diskless'>diskless</option>\
57 var DEFAULT_NIC_MODE = undefined;
58 var DEFAULT_NIC_LINK = undefined;
63 this.init = function(cluster_defaults){
64 /* initialize the live form updater */
66 // disable the iallocator stuff by default
67 if(!iallocator_hostname.attr("value")){
68 iallocator.attr("readonly", "readonly");
72 using_str + iallocator_hostname.val() +
77 // only disable iallocator by default if there is no cluster selected
78 // or the cluster already selected does not support iallocator
79 var def_iallocator = cluster_defaults['iallocator'];
80 if (!iallocator.is(":checked")
81 && (def_iallocator == undefined|| def_iallocator == '')
86 // hide CD-ROM Image Path stuffs by default
89 // setup form element change hooks
92 //recover from form error
93 if(no_install.is(":checked")){
97 // fire off some initial changes
100 disk_template.change();
104 disableSingletonDropdown($("#id_pnode"), blankOptStr);
105 // process the owner dropdown, i.e., if it only has a single option,
106 // select it, and make the dropdown read-only
107 disableSingletonDropdown(owner, blankOptStr);
108 disableSingletonDropdown(hypervisor, blankOptStr);
109 disableSingletonDropdown(cluster, blankOptStr);
112 function _initChangeHooks(){
113 /* setup change hooks for the form elements */
115 // handle hypervisor changes
116 hypervisor.live("change", function() {
117 var id = $(this).val();
118 if (id == "xen-hvm") {
119 _showHvmKvmElements();
120 _hidePvmKvmElements();
123 else if (id == "xen-pvm") {
124 _showPvmKvmElements();
125 _hideHvmKvmElements();
128 else if (id == "kvm") {
130 _showHvmKvmElements();
131 _showPvmKvmElements();
135 // boot device change
136 boot_order.live("change", function(){
138 Only show image path stuffs if CD-ROM is selected in the boot
141 var id = $(this).children("option:selected").val();
150 iallocator.live("change", function() {
151 if(!iallocator.attr("readonly")) {
152 if(iallocator.is(":checked")) {
160 if(!iallocator.is(":checked")){
163 disk_template.parent("p").show();
164 disk_template.change();
169 // disk_template change
170 disk_template.live("change", function() {
171 if(!iallocator.is(":checked") ||
172 iallocator.attr("readonly")) {
174 if(disk_template.val() == "drbd" && nodes.length > 1){
181 if (disk_template.val() == 'diskless') {
184 disks.find('input[name^=disk_size]').attr('disabled','disabled');
185 } else if (!disks.is(":visible") || true) {
187 disks.find('input[name^=disk_size]').removeAttr('disabled');
188 disk_count.val(disks.find('input[name^=disk_size]').length);
193 owner.live("change", function() {
194 var id = $(this).children("option:selected").val();
196 // JSON update the cluster when the owner changes
197 _cached_get(url_choices, {"clusteruser_id":id}, _update_cluster_choices);
202 no_install.live("change",function() {
203 if(no_install.is(":checked")){
212 cluster.live("change", function() {
213 var id = $(this).children("option:selected").val();
215 // JSON update oslist, pnode, and snode when cluster changes
216 _cached_get(url_options, {"cluster_id":id}, _update_options);
218 // only load the defaults if errors are not present
219 if($(".errorlist").length == 0){
220 _fillDefaultOptions(id);
225 disk_add.click(_add_disk);
226 disk_delete.live("click",_remove_disk);
227 nic_add.click(_add_nic);
228 nic_delete.live("click",_remove_nic);
235 function _update_cluster_choices(data){
236 var old_cluster = cluster.val();
238 cluster.children().not(":first").remove();
239 $.each(data, function(i, item) {
240 cluster.append(_newOpt(item[0], item[1]));
243 // Try to re-select the previous cluster, if possible. else just trigger
244 // a change so cluster update logic is run
245 if (cluster.children('option[value='+old_cluster+']').length) {
246 cluster.val(old_cluster);
251 // process dropdown if its a singleton
252 disableSingletonDropdown(cluster, blankOptStr);
255 function _update_options(data) {
256 var pnode = $("#id_pnode");
257 var snode = $("#id_snode");
258 var oslist = $("#id_os");
260 var oldpnode = pnode.val();
261 var oldsnode = snode.val();
262 var oldos = oslist.val();
263 var old_template = disk_template.val();
265 pnode.children().not(":first").remove();
266 snode.children().not(":first").remove();
267 oslist.children().not(":first").remove();
268 $.each(data, function(i, items) {
269 $.each(items, function(key, value) {
271 child = _newOpt(value, value);
272 child2 = child.clone();
274 snode.append(child2);
276 else if (i == "os") {
277 child = _newOptGroup(value[0],
279 oslist.append(child);
284 // make nodes publically available
285 nodes = data["nodes"];
287 // update disk template choices
288 disk_template.empty();
289 if (nodes.length == 1){
290 disk_template.html(single_node_template_choices);
292 disk_template.html(template_choices);
295 // Restore old choices from before, if possible.
299 disk_template.val(old_template);
301 // And finally, do the singleton dance.
302 disableSingletonDropdown(pnode, blankOptStr);
303 disableSingletonDropdown(snode, blankOptStr);
304 disableSingletonDropdown(oslist, blankOptStr);
307 function _update_cluster_defaults(d){
308 /* fill default options */
310 // boot device dropdown
311 if(d["boot_devices"]) {
312 boot_order.children().remove();
313 $.each(d["boot_devices"], function(i, item){
314 boot_order.append(_newOpt(item[0], item[1]));
317 if(d["boot_order"]) {
318 boot_order.find(":selected").removeAttr(
320 boot_order.find("[value=" + d["boot_order"] + "]")
321 .attr("selected","selected");
325 // hypervisors dropdown
326 if(d["hypervisors"]) {
327 hypervisor.children().remove();
328 $.each(d["hypervisors"], function(i, item){
329 hypervisor.append(_newOpt(item[0], item[1]));
331 if(d["hypervisor"]) {
332 if (d["hypervisor"] != "" &&
333 d["hypervisor"] != undefined) {
334 hypervisor.find(":selected").removeAttr("selected");
335 hypervisor.find("[value=" + d["hypervisor"] + "]")
336 .attr("selected", "selected");
340 disableSingletonDropdown(hypervisor, blankOptStr);
343 // iallocator checkbox
344 if(d["iallocator"] != "" &&
345 d["iallocator"] != undefined){
346 if(!iallocator_hostname.attr("value")) {
347 iallocator_hostname.attr("value",
349 if(iallocator.siblings("span").length == 0){
351 "<span>" + using_str +
357 // Check iallocator checkbox
358 iallocator.parent("p").show();
359 iallocator.removeAttr("disabled")
360 .removeAttr("readonly")
361 .attr("checked", "checked")
364 _iallocatorDisable();
367 // kernel path text box
368 if(d["kernel_path"]){
369 kernel_path.val(d["kernel_path"]);
374 nic_mode.find(":selected").removeAttr("selected");
375 nic_mode.find("[value=" + d["nic_mode"] + "]")
376 .attr("selected","selected");
377 DEFAULT_NIC_MODE = d["nic_mode"];
379 nic_mode.find(":first-child")
380 .attr("selected", "selected");
385 nic_link.val(d["nic_link"]);
386 DEFAULT_NIC_LINK = d["nic_link"];
391 nic_type.children().remove();
392 $.each(d["nic_types"], function(i, item){
393 nic_type.append(_newOpt(item[0], item[1]));
397 nic_type.find(":selected").removeAttr("selected");
398 nic_type.find("[value=" + d["nic_type"] + "]")
399 .attr("selected","selected");
403 if($("#id_memory") == "" && d["memory"]){
404 $("#id_memory").val(d["memory"]);
407 // disk type dropdown
409 disk_type.children().remove();
410 $.each(d["disk_types"], function(i, item){
411 disk_type.append(_newOpt(item[0], item[1]));
414 disk_type.val(d["disk_type"]);
418 // root path text box
420 root_path.val(d["root_path"]);
425 // enable serial console checkbox
426 if(d["serial_console"]){
427 $("#id_serial_console")
428 .attr("checked", "checked");
430 $("#id_serial_console").removeAttr("checked");
433 // virtual CPUs text box
434 if($("#id_vcpus").val() == "" && d["vcpus"]){
435 $("#id_vcpus").val(d["vcpus"]);
438 // image path text box
439 if(d["cdrom_image_path"]){
440 image_path.find("input").val(d["cdrom_image_path"]);
443 if(d["cdrom2_image_path"]){
444 image2_path.find("input").val(d["cdrom2_image_path"]);
448 function _fillDefaultOptions(cluster_id) {
449 var args = new Object();
450 args["cluster_id"] = cluster_id;
451 var _hypervisor = hypervisor.val();
452 if (_hypervisor != '') {
453 args["hypervisor"] = _hypervisor;
455 _cached_get(url_defaults, args, _update_cluster_defaults);
458 function _imagePathHide(){
463 function _imagePathShow(){
468 function _iallocatorDisable(){
469 /* Disable and hide all of the iallocator stuffs */
470 iallocator.parent("p").hide();
471 iallocator_hostname.removeAttr("value")
473 iallocator.attr("disabled", "disabled")
474 .removeAttr("checked")
478 function _newOpt(value, text) {
479 /* Create new option items for select field */
480 var o = $("<option></option>");
481 o.attr("value", value);
482 o.attr("text", text);
486 function _newOptGroup(value, options) {
487 /* Create new option group for select field */
488 var group = $("<optgroup></optgroup>");
489 group.attr("label", value);
490 $.each(options, function(i, option) {
491 group.append(_newOpt(option[0], option[1]));
496 function _hideHvmKvmElements() {
497 // Hide hvm + kvm specific hypervisor fields
498 boot_order.parent("p").hide();
500 nic_type.parent("p").hide();
501 disk_type.parent("p").hide();
504 function _showHvmKvmElements() {
505 // Show hvm + kvm specific hypervisor fields
506 boot_order.parent("p").show();
508 nic_type.parent("p").show();
509 disk_type.parent("p").show();
512 function _hidePvmKvmElements() {
513 // Hide pvm specific hypervisor fields
514 root_path.parent("p").hide();
515 kernel_path.parent("p").hide();
518 function _showPvmKvmElements() {
519 // Show pvm specific hypervisor fields
520 root_path.parent("p").show();
521 kernel_path.parent("p").show();
524 function _hideKvmElements() {
525 // Hide kvm specific hypervisor fields
526 serial_console.hide();
529 function _showKvmElements() {
530 // Show kvm specific hypervisor fields
531 serial_console.show();
534 function _add_disk() {
535 var count = disk_count.val();
536 disk_count.val(parseInt(count)+1);
537 var p = $('<p></p>');
538 var label = $("<label>Disk/" + count+ " Size</label>");
539 label.attr('for', "id_disk_size_" + count);
540 var input = $('<input type="text"/>');
541 input.attr("name", "disk_size_" + count);
542 input.attr("id", "id_disk_size_" + count);
546 disks.append('<div class="icon delete"></div>');
549 function _remove_disk() {
550 var count = disk_count.val();
551 disk_count.val(parseInt(count)-1);
552 var button = $(this);
553 button.prev("p").remove();
554 button.prev("ul").remove();
557 // renumber remaining disks
559 $('#disks p').each(function(){
560 $(this).children('label')
561 .html("Disk/" + i + " Size")
562 .attr("for", "id_disk_size_" + i);
563 $(this).children('#disks input[name^=disk_size]').each(function(){
565 .attr("name", "disk_size_" + i)
566 .attr("id", "id_disk_size_" + i);
572 function _add_nic() {
573 var count = nic_count.val();
574 nic_count.val(parseInt(count)+1);
575 var p = $('<p></p>');
576 var label = $("<label>NIC/" + count +"</label>");
578 // create mode select box
579 var mode = $('<select></select>');
580 mode.append('<option>----------</option>');
581 mode.append('<option value="bridged">bridged</option>');
582 mode.append('<option value="routed">routed</option>');
583 mode.attr("name", "nic_mode_" + count);
584 mode.attr("id", "id_nic_mode_" + count);
585 if (DEFAULT_NIC_LINK != undefined) {
586 mode.val(DEFAULT_NIC_MODE);
590 var link = $("<input type='text'/>");
591 link.val(DEFAULT_NIC_LINK);
592 link.attr("name", "nic_link_" + count);
593 link.attr("id", "id_nic_link_" + count);
594 if (DEFAULT_NIC_LINK != undefined) {
595 mode.val(DEFAULT_NIC_MODE);
601 nics.append('<div class="icon delete"></div>');
604 function _remove_nic() {
605 var count = nic_count.val();
606 nic_count.val(parseInt(count)-1);
607 var button = $(this);
608 button.prev("p").remove();
609 button.prev("ul").remove();
612 // renumber remaining disks
614 $('#nics p').each(function(){
615 $(this).children('label')
617 $(this).children('input[name^=nic_link]').each(function(){
619 .attr("name", "nic_link_" + i)
620 .attr("id", "id_nic_link_" + i);
622 $(this).children('select[name^=nic_mode]').each(function(){
624 .attr("name", "nic_mode_" + i)
625 .attr("id", "id_nic_mode_" + i);
632 function _cached_get(url, data, callback) {
633 var key = _encode_url(url, data);
634 var response = AJAX_CACHE[key];
635 if (response == undefined ) {
637 // create a callback function that will execute for all calls to
638 // this url. helps deal with multiple simultaneous calls to a url
639 var _callback = function(response, status, xhr) {
640 AJAX_CACHE[key] = response;
641 var callbacks = _callback.callbacks;
642 for (var i in callbacks) {
643 callbacks[i](response, status, xhr);
647 // add callback to generic callback function
648 _callback.callbacks = [];
649 if (callback != undefined) {
650 _callback.callbacks.push(callback);
653 $.getJSON(url, data, _callback);
654 AJAX_CACHE[key] = _callback;
655 } else if (callback != undefined) {
656 if (response.callbacks != undefined) {
657 _push_unique(response.callbacks, callback);
664 function _push_unique(array, item) {
665 for (var i in array) {
666 if (array[i] == item) {
673 function _encode_url(url, data)
677 ret.push(encodeURIComponent(d) + "=" + encodeURIComponent(data[d]));
678 return url+'?'+ret.join("&");