Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ 41cad45d

History | View | Annotate | Download (17.8 kB)

1
var flavors = [], images = [], servers = [], disks = [], cpus = [], ram = [];
2
var changes_since = 0, deferred = 0, update_request = false, load_request = false, pending_actions = [];
3
var API_URL = "/api/v1.1redux";
4

    
5
function ISODateString(d){
6
    //return a date in an ISO 8601 format using UTC. 
7
    //do not include time zone info (Z) at the end
8
    //taken from the Mozilla Developer Center 
9
    function pad(n){ return n<10 ? '0'+n : n }
10
    return  d.getUTCFullYear()+ '-' +
11
                        pad(d.getUTCMonth()+1) + '-' +
12
                        pad(d.getUTCDate()) + 'T' +
13
                        pad(d.getUTCHours()) + ':' +
14
                        pad(d.getUTCMinutes())+ ':' +
15
                        pad(d.getUTCSeconds())
16
}
17

    
18
// indexOf prototype for IE
19
if (!Array.prototype.indexOf) {
20
  Array.prototype.indexOf = function(elt /*, from*/) {
21
    var len = this.length;
22
    var from = Number(arguments[1]) || 0;
23
    from = (from < 0)
24
         ? Math.ceil(from)
25
         : Math.floor(from);
26
    if (from < 0)
27
      from += len;
28

    
29
    for (; from < len; from++) {
30
      if (from in this &&
31
          this[from] === elt)
32
        return from;
33
    }
34
    return -1;
35
  };
36
}
37

    
38

    
39
function update_confirmations(){
40
    // hide all confirm boxes to begin with
41
    $('div.confirm_single').hide();
42
    $('div.confirm_multiple').hide();
43
   
44
        // standard view only
45
        if ($.cookie("list") != '1') { 
46
                for (i=0;i<pending_actions.length;i++){
47
            // show single confirms
48
                        $("div.machine#"+pending_actions[i][1]+' .confirm_single').show();        
49
                }                
50
        }
51

    
52
        // if more than one pending action show multiple confirm box
53
        if (pending_actions.length>1 || $.cookie("list") == '1' && pending_actions.length == 1){ 
54
                $('div.confirm_multiple span.actionLen').text(pending_actions.length);
55
                $('div.confirm_multiple').show();
56
        }
57
}
58

    
59
function list_view() {
60
        changes_since = 0; // to reload full list
61
        pending_actions = []; // clear pending actions
62
        update_confirmations();
63
        clearTimeout(deferred);        // clear old deferred calls
64
        try {
65
                update_request.abort(); // cancel pending ajax updates
66
                load_request.abort();
67
        }catch(err){}
68
    $.cookie("list", '1'); // set list cookie
69
        
70
        uri = $("#list").attr("href");
71
    load_request = $.ajax({
72
        url: uri,
73
        type: "GET",
74
        timeout: TIMEOUT,
75
        dataType: "html",
76
        error: function(jqXHR, textStatus, errorThrown) {                                                
77
                        return false;
78
                },
79
        success: function(data, textStatus, jqXHR) {
80
                        $("a#standard")[0].className += ' activelink';
81
                        $("a#list")[0].className = '';
82
                        $("div#machinesview").html(data);
83
                }
84
        });
85
    
86
    return false;
87
}
88

    
89
function standard_view() {
90
        changes_since = 0; // to reload full list
91
        pending_actions = []; // clear pending actions
92
        update_confirmations();
93
        clearTimeout(deferred);        // clear old deferred calls
94
        try {
95
                update_request.abort() // cancel pending ajax updates
96
                load_request.abort();
97
        }catch(err){}        
98
    $.cookie("list", '0');
99
        
100
    uri = $("a#standard").attr("href");
101
    load_request = $.ajax({
102
        url: uri,
103
        type: "GET",
104
        timeout: TIMEOUT,
105
        dataType: "html",
106
        error: function(jqXHR, textStatus, errorThrown) {                                                
107
                        return false;
108
                },
109
        success: function(data, textStatus, jqXHR) {
110
                        $("a#list")[0].className += ' activelink';
111
                        $("a#standard")[0].className = '';
112
                        $("div#machinesview").html(data);
113
                }
114
        });        
115

    
116
    return false;
117
}
118

    
119
function choose_view() {
120
    if ($.cookie("list")=='1') {
121
        list_view();
122
    } else {
123
        standard_view();
124
    }
125
}
126

    
127
function toggleMenu() {
128
    var primary = $("ul.css-tabs li a.primary");
129
    var secondary = $("ul.css-tabs li a.secondary");
130
    var all = $("ul.css-tabs li a");                        
131
    var toggled = $('ul.css-tabs li a.current').hasClass('secondary');
132
    
133
    // if anything is still moving, do nothing
134
    if ($(":animated").length) {
135
        return;
136
    } 
137
    
138
    // nothing is current to begin with
139
    $('ul.css-tabs li a.current').removeClass('current');
140
    
141
    // move stuff around
142
    all.animate({top:'30px'}, {complete: function() { 
143
        $(this).hide();
144
        if (toggled) {
145
            primary.show();
146
            primary.animate({top:'9px'}, {complete: function() {
147
                $('ul.css-tabs li a.primary#machines').addClass('current');
148
                $('a#machines').click();                                   
149
            }});
150
        } else {
151
            secondary.show();
152
            secondary.animate({top:'9px'}, {complete: function() {
153
                $('ul.css-tabs li a.secondary#files').addClass('current');
154
                $('a#files').click();                                                                           
155
            }});
156
        }                                              
157
    }});
158
    
159
    // rotate arrow icon
160
    if (toggled) {
161
        $("#arrow").rotate({animateAngle: (0), bind:[{"click":function(){toggleMenu()}}]});
162
        $("#arrow").rotateAnimation(0);                    
163
    } else {
164
        $("#arrow").rotate({animateAngle: (-180), bind:[{"click":function(){toggleMenu()}}]});
165
        $("#arrow").rotateAnimation(-180);
166
    }            
167
}
168

    
169
// confirmation overlay generation
170
function confirm_action(action_string, action_function, serverIDs, serverNames) {
171
    if (serverIDs.length == 1){
172
        $("#yes-no h3").text('You are about to ' + action_string + ' vm ' + serverNames[0]);
173
    } else if (serverIDs.length > 1){
174
        $("#yes-no h3").text('You are about to ' + action_string + ' ' + serverIDs.length + ' machines');
175
    } else {
176
        return false;
177
    }
178
    // action confirmation overlay
179
    var triggers = $("a#confirmation").overlay({
180
            // some mask tweaks suitable for modal dialogs
181
            mask: {
182
                    color: '#ebecff',
183
                    opacity: '0.9'
184
            },
185
        top: 'center',
186
        load: false
187
    });
188
    // yes or no?
189
    var buttons = $("#yes-no button").click(function(e) {
190
            // get user input
191
            var yes = buttons.index(this) === 0;
192
        //close the confirmation window
193
        $("a#confirmation").overlay().close(); 
194
        // return true=yes or false=no
195
        if (yes) {
196
            action_function(serverIDs);
197
        }
198
    });
199
    $("a#confirmation").data('overlay').load();
200
    return false;
201
}
202

    
203
// get and show a list of running and terminated machines
204
function update_vms(interval) {
205
    try{ console.info('updating machines'); } catch(err){}
206
        var uri='/api/v1.0/servers/detail';
207
        
208
        if (changes_since != 0)
209
                uri+='?changes-since='+changes_since
210
                
211
    update_request = $.ajax({
212
        url: uri,
213
        type: "GET",
214
        timeout: TIMEOUT,
215
        dataType: "json",
216
        error: function(jqXHR, textStatus, errorThrown) {
217
                        // don't forget to try again later
218
                        if (interval) {
219
                                clearTimeout(deferred);        // clear old deferred calls
220
                                deferred = setTimeout(update_vms,interval,interval);
221
                        }
222
                        // as for now, just show an error message
223
                        try { console.info('update_vms errback:' + jqXHR.status ) } catch(err) {}
224
                        ajax_error(jqXHR.status);                                                
225
                        return false;
226
                        },
227
        success: function(data, textStatus, jqXHR) {
228
                        // create changes_since string if necessary
229
                        if (jqXHR.getResponseHeader('Date') != null){
230
                                changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
231
                                changes_since = ISODateString(changes_since_date);
232
                        }
233
                        
234
                        if (interval) {
235
                                clearTimeout(deferred);        // clear old deferred calls
236
                                deferred = setTimeout(update_vms,interval,interval);
237
                        }
238
                        
239
                        if (jqXHR.status == 200 || jqXHR.status == 203) {
240
                                try {
241
                                        servers = data.servers;
242
                                } catch(err) { ajax_error('400');}
243
                                update_machines_view(data);
244
                        } else if (jqXHR.status != 304){
245
                                try { console.info('update_vms callback:' + jqXHR.status ) } catch(err) {}
246
                                //ajax_error();                                                
247
                        }
248
                        return false;
249
        }
250
    });
251
    return false;
252
}
253

    
254
// get and show a list of available standard and custom images
255
function update_images() { 
256
    $.ajax({
257
        url: '/api/v1.0/images/detail',
258
        type: "GET",
259
        //async: false,
260
        dataType: "json",
261
        timeout: TIMEOUT,
262
        error: function(jqXHR, textStatus, errorThrown) { 
263
                    ajax_error(jqXHR.status);
264
                    },
265
        success: function(data, textStatus, jqXHR) {
266
            try {
267
                                images = data.images;
268
                                update_wizard_images();
269
                        } catch(err){
270
                                ajax_error("NO_IMAGES");
271
                        }
272
        }
273
    });
274
    return false;
275
}
276

    
277
function update_wizard_images() {
278
        if ($("ul#standard-images li").toArray().length + $("ul#custom-images li").toArray().length == 0) {
279
                $.each(images, function(i,image){
280
                        var img = $('#image-template').clone().attr("id","img-"+image.id).fadeIn("slow");
281
                        img.find("label").attr('for',"img-radio-" + image.id);
282
                        img.find(".image-title").text(image.name);
283
                        img.find(".description").text(image.metadata.meta.key.description);
284
                        img.find(".size").text(image.size);
285
                        img.find("input.radio").attr('id',"img-radio-" + image.id);
286
                        if (i==0) img.find("input.radio").attr("checked","checked"); 
287
                        img.find("img.image-logo").attr('src','static/os_logos/'+image_tags[image.id]+'.png');
288
                        if (image.serverId) {
289
                                img.appendTo("ul#custom-images");
290
                        } else {
291
                                img.appendTo("ul#standard-images");
292
                        }
293
                });
294
        }        
295
}
296

    
297
function update_wizard_flavors(){
298
        // sliders for selecting VM flavor
299
        $("#cpu:range").rangeinput({min:0,
300
                                                           value:0,
301
                                                           step:1,
302
                                                           progress: true,
303
                                                           max:cpus.length-1});
304
        
305
        $("#storage:range").rangeinput({min:0,
306
                                                           value:0,
307
                                                           step:1,
308
                                                           progress: true,
309
                                                           max:disks.length-1});
310

    
311
        $("#ram:range").rangeinput({min:0,
312
                                                           value:0,
313
                                                           step:1,
314
                                                           progress: true,
315
                                                           max:ram.length-1});
316
        $("#small").click();
317
        
318
        // update the indicators when sliding
319
        $("#cpu:range").data().rangeinput.onSlide(function(event,value){
320
                $("#cpu-indicator")[0].value = cpus[Number(value)];
321
        });
322
        $("#cpu:range").data().rangeinput.change(function(event,value){
323
                $("#cpu-indicator")[0].value = cpus[Number(value)];                                
324
                $("#custom").click();                                
325
        });                        
326
        $("#ram:range").data().rangeinput.onSlide(function(event,value){
327
                $("#ram-indicator")[0].value = ram[Number(value)];
328
        });
329
        $("#ram:range").data().rangeinput.change(function(event,value){
330
                $("#ram-indicator")[0].value = ram[Number(value)];                                
331
                $("#custom").click();
332
        });                        
333
        $("#storage:range").data().rangeinput.onSlide(function(event,value){
334
                $("#storage-indicator")[0].value = disks[Number(value)];
335
        });
336
        $("#storage:range").data().rangeinput.change(function(event,value){
337
                $("#storage-indicator")[0].value = disks[Number(value)];                                
338
                $("#custom").click();
339
        });                                
340
}
341

    
342
Array.prototype.unique = function () {
343
        var r = new Array();
344
        o:for(var i = 0, n = this.length; i < n; i++)
345
        {
346
                for(var x = 0, y = r.length; x < y; x++)
347
                {
348
                        if(r[x]==this[i])
349
                        {
350
                                continue o;
351
                        }
352
                }
353
                r[r.length] = this[i];
354
        }
355
        return r;
356
}
357

    
358
// get and configure flavor selection
359
function update_flavors() { 
360
    $.ajax({
361
        url: API_URL + '/flavors/detail',
362
        type: "GET",
363
        //async: false,
364
        dataType: "json",
365
        timeout: TIMEOUT,
366
        error: function(jqXHR, textStatus, errorThrown) { 
367
            try {
368
                                ajax_error(jqXHR.status);
369
                        } catch (err) {
370
                                ajax_error(err);
371
                        }
372
        },
373
        success: function(data, textStatus, jqXHR) {
374
            flavors = data.flavors.values;
375
            $.each(flavors, function(i, flavor) {
376
                cpus[i] = flavor['cpu'];
377
                disks[i] = flavor['disk'];
378
                ram[i] = flavor['ram'];
379
            });
380
            cpus = cpus.unique();
381
            disks = disks.unique();
382
            ram = ram.unique();
383
                        update_wizard_flavors();
384
        }
385
    });
386
    return false;
387
}
388

    
389
// return flavorRef from cpu, disk, ram values
390
function identify_flavor(cpu, disk, ram){
391
    for (i=0;i<flavors.length;i++){
392
        if (flavors[i]['cpu'] == cpu && flavors[i]['disk']==disk && flavors[i]['ram']==ram) {
393
            return flavors[i]['id']
394
        }
395
    }
396
    return 0;
397
}
398

    
399
// update the actions in list view
400
function updateActions() {
401
        var states = [];
402
        var on = [];
403
        var checked = $("table.list-machines tbody input[type='checkbox']:checked");
404
        // disable all actions to begin with
405
        for (action in actions) {
406
                $("#action-" + action).removeClass('enabled');
407
        }
408

    
409
        // are there multiple machines selected?
410
        if (checked.length>1)
411
                states[0] = 'multiple';
412
        
413
        // check the states of selected machines
414
        checked.each(function(i,checkbox) {
415
                states[states.length] = checkbox.className;
416
                var ip = $("#" + checkbox.id.replace('input-','') + ".ip span.public").text();
417
                if (ip.replace('undefined','').length)
418
                        states[states.length] = 'network';
419
        });
420

    
421
        // decide which actions should be enabled
422
        for (a in actions) {
423
                var enabled = false;
424
                for (var s =0; s<states.length; s++) {
425
                        if (actions[a].indexOf(states[s]) != -1 ) {
426
                                enabled = true;
427
                        } else {
428
                                enabled = false;
429
                                break;
430
                        }
431
                }
432
                if (enabled)
433
                        on[on.length]=a;
434
        }
435
        // enable those actions
436
        for (action in on) {
437
                $("#action-" + on[action]).addClass('enabled');
438
        }
439
}
440

    
441
//create server action
442
function create_vm(machineName, imageRef, flavorRef){
443
    var payload = {
444
        "server": {
445
            "name": machineName,
446
            "imageRef": imageRef,
447
            "flavorRef" : flavorRef,
448
            "metadata" : {
449
                "My Server Name" : machineName
450
            },
451
        }
452
    };
453

    
454

    
455
    $.ajax({
456
    url: "/api/v1.0/servers",
457
    type: "POST",
458
    dataType: "json",    
459
    data: JSON.stringify(payload),
460
    timeout: TIMEOUT,
461
    error: function(jqXHR, textStatus, errorThrown) { 
462
                ajax_error(jqXHR.status);
463
           },
464
    success: function(data, textStatus, jqXHR) {
465
                if ( jqXHR.status == '202') {
466
                    ajax_success("CREATE_VM_SUCCESS", data.server.adminPass);                   
467
                } else {
468
                    ajax_error(jqXHR.status);
469
                }
470
            }
471
    });
472
}
473

    
474
// reboot action
475
function reboot(serverIDs){
476
        if (!serverIDs.length){
477
                //ajax_success('DEFAULT');
478
                return false;
479
        }        
480
    // ajax post reboot call
481
    var payload = {
482
        "reboot": {"type" : "HARD"}
483
    };
484
    var serverID = serverIDs.pop();
485
        
486
        $.ajax({
487
                url: API_URL + '/servers/' + serverID + '/action',
488
                type: "POST",        
489
                dataType: "json",
490
                data: JSON.stringify(payload),
491
                timeout: TIMEOUT,
492
                error: function(jqXHR, textStatus, errorThrown) {
493
                    display_failure(serverID, jqXHR.status, 'Reboot')
494
                                },
495
                success: function(data, textStatus, jqXHR) {
496
                                        if ( jqXHR.status == '202') {
497
                        try {
498
                            console.info('rebooted ' + serverID);
499
                        } catch(err) {}
500
                                                // indicate that the action succeeded
501
                                                display_success(serverID);
502
                                                // continue with the rest of the servers
503
                                                reboot(serverIDs);
504
                                        } else {
505
                                                ajax_error(jqXHR.status, serverID);
506
                                        }
507
                                }
508
    });
509

    
510
    return false;
511
}
512

    
513
// shutdown action
514
function shutdown(serverIDs) {
515
        if (!serverIDs.length){
516
                //ajax_success('DEFAULT');
517
                return false;
518
        }
519
    // ajax post shutdown call
520
    var payload = {
521
        "shutdown": {"timeout" : "5"}
522
    };   
523

    
524
        var serverID = serverIDs.pop()
525
    $.ajax({
526
            url: API_URL + '/servers/' + serverID + '/action',
527
            type: "POST",
528
            dataType: "json",
529
        data: JSON.stringify(payload),
530
        timeout: TIMEOUT,
531
        error: function(jqXHR, textStatus, errorThrown) { 
532
                    display_failure(serverID, jqXHR.status, 'Shutdown')
533
                    },
534
        success: function(data, textStatus, jqXHR) {
535
                    if ( jqXHR.status == '202') {
536
                                                try {
537
                            console.info('suspended ' + serverID);
538
                        } catch(err) {}
539
                                                // indicate that the action succeeded
540
                                                display_success(serverID);
541
                                                // continue with the rest of the servers                        
542
                        shutdown(serverIDs);
543
                    } else {
544
                        ajax_error(jqXHR.status, serverID);
545
                    }
546
                }             
547
    });
548

    
549
    return false;    
550
}
551

    
552
// destroy action
553
function destroy(serverIDs) {
554
        if (!serverIDs.length){
555
                //ajax_success('DEFAULT');
556
                return false;
557
        }
558
    // ajax post destroy call can have an empty request body
559
    var payload = {};   
560

    
561
        serverID = serverIDs.pop()
562
    $.ajax({
563
            url: API_URL + '/servers/' + serverID,
564
            type: "DELETE",
565
            dataType: "json",
566
        data: JSON.stringify(payload),
567
        timeout: TIMEOUT,
568
        error: function(jqXHR, textStatus, errorThrown) { 
569
                    display_failure(serverID, jqXHR.status, 'Destroy')
570
                    },
571
        success: function(data, textStatus, jqXHR) {
572
                    if ( jqXHR.status == '204') {
573
                                                try {
574
                            console.info('destroyed ' + serverID);
575
                        } catch (err) {}
576
                                                // indicate that the action succeeded
577
                                                display_success(serverID);
578
                                                // continue with the rest of the servers
579
                        destroy(serverIDs);
580
                    } else {
581
                        ajax_error(jqXHR.status, serverID);
582
                    }
583
                }             
584
    });
585

    
586
    return false;    
587
}
588

    
589
// start action
590
function start(serverIDs){
591
        if (!serverIDs.length){
592
                //ajax_success('DEFAULT');
593
                return false;
594
        }        
595
    // ajax post start call
596
    var payload = {
597
        "start": {"type" : "NORMAL"}
598
    };   
599

    
600
        var serverID = serverIDs.pop()
601
    $.ajax({
602
        url: API_URL + '/servers/' + serverID + '/action',
603
        type: "POST",
604
        dataType: "json",
605
        data: JSON.stringify(payload),
606
        timeout: TIMEOUT,
607
        error: function(jqXHR, textStatus, errorThrown) { 
608
                    display_failure(serverID, jqXHR.status, 'Start')
609
                    },
610
        success: function(data, textStatus, jqXHR) {
611
                    if ( jqXHR.status == '202') {
612
                                            try {
613
                            console.info('started ' + serverID);
614
                        } catch(err) {}
615
                                                // indicate that the action succeeded
616
                                                display_success(serverID);
617
                                                // continue with the rest of the servers                                                
618
                        start(serverIDs);
619
                    } else {
620
                        ajax_error(jqXHR.status, serverID);
621
                    }
622
                }
623
    });
624

    
625
    return false;
626
}