Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ 5fa5c0b2

History | View | Annotate | Download (16.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

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

    
17
function update_confirmations(){
18
    $('div.confirm_single').hide(); // hide all confirm boxes to begin with
19
    $('div.confirm_multiple').hide();
20
    
21
        // standard view only
22
        if ($.cookie("list") != '1') { 
23
                for (i=0;i<pending_actions.length;i++){ // show single confirms
24
                        $("div.machine#"+pending_actions[i][1]+' .confirm_single').show();        
25
                }                
26
        }
27
        
28
        if (pending_actions.length>1 || $.cookie("list") == '1' && pending_actions.length == 1){ // if more than one pending action show multiple confirm box
29
                $('div.confirm_multiple span.actionLen').text(pending_actions.length);
30
        // set the label of the buttons in list view
31
        if ($.cookie("list") == '1') {
32
            $('div.confirm_multiple button.yes').text('Confirm');
33
            $('div.confirm_multiple button.no').text('Cancel');
34
        }
35
        // set the label of the buttons in standard view
36
        else {
37
            $('div.confirm_multiple button.yes').text('Confirm All');
38
            $('div.confirm_multiple button.no').text('Cancel All');
39
        }
40
                $('div.confirm_multiple').show();
41
        }
42
}
43

    
44
function list_view() {
45
        changes_since = 0; // to reload full list
46
        pending_actions = []; // clear pending actions
47
        update_confirmations();
48
        clearTimeout(deferred);        // clear old deferred calls
49
        try {
50
                update_request.abort(); // cancel pending ajax updates
51
                load_request.abort();
52
        }catch(err){}
53
    $.cookie("list", '1'); // set list cookie
54
        
55
        uri = $("#list").attr("href");
56
    load_request = $.ajax({
57
        url: uri,
58
        type: "GET",
59
        timeout: TIMEOUT,
60
        dataType: "html",
61
        error: function(jqXHR, textStatus, errorThrown) {                                                
62
                        return false;
63
                },
64
        success: function(data, textStatus, jqXHR) {
65
                        $("a#standard")[0].className += ' activelink';
66
                        $("a#list")[0].className = '';
67
                        $("div#machinesview").html(data);
68
                }
69
        });
70
    
71
    return false;
72
}
73

    
74
function standard_view() {
75
        changes_since = 0; // to reload full list
76
        pending_actions = []; // clear pending actions
77
        update_confirmations();
78
        clearTimeout(deferred);        // clear old deferred calls
79
        try {
80
                update_request.abort() // cancel pending ajax updates
81
                load_request.abort();
82
        }catch(err){}        
83
    $.cookie("list", '0');
84
        
85
    uri = $("a#standard").attr("href");
86
    load_request = $.ajax({
87
        url: uri,
88
        type: "GET",
89
        timeout: TIMEOUT,
90
        dataType: "html",
91
        error: function(jqXHR, textStatus, errorThrown) {                                                
92
                        return false;
93
                },
94
        success: function(data, textStatus, jqXHR) {
95
                        $("a#list")[0].className += ' activelink';
96
                        $("a#standard")[0].className = '';
97
                        $("div#machinesview").html(data);
98
                }
99
        });        
100

    
101
    return false;
102
}
103

    
104
function choose_view() {
105
    if ($.cookie("list")=='1') {
106
        list_view();
107
    } else {
108
        standard_view();
109
    }
110
}
111

    
112
function toggleMenu() {
113
    var primary = $("ul.css-tabs li a.primary");
114
    var secondary = $("ul.css-tabs li a.secondary");
115
    var all = $("ul.css-tabs li a");                        
116
    var toggled = $('ul.css-tabs li a.current').hasClass('secondary');
117
    
118
    // if anything is still moving, do nothing
119
    if ($(":animated").length) {
120
        return;
121
    } 
122
    
123
    // nothing is current to begin with
124
    $('ul.css-tabs li a.current').removeClass('current');
125
    
126
    // move stuff around
127
    all.animate({top:'30px'}, {complete: function() { 
128
        $(this).hide();
129
        if (toggled) {
130
            primary.show();
131
            primary.animate({top:'9px'}, {complete: function() {
132
                $('ul.css-tabs li a.primary#machines').addClass('current');
133
                $('a#machines').click();                                   
134
            }});
135
        } else {
136
            secondary.show();
137
            secondary.animate({top:'9px'}, {complete: function() {
138
                $('ul.css-tabs li a.secondary#files').addClass('current');
139
                $('a#files').click();                                                                           
140
            }});
141
        }                                              
142
    }});
143
    
144
    // rotate arrow icon
145
    if (toggled) {
146
        $("#arrow").rotate({animateAngle: (0), bind:[{"click":function(){toggleMenu()}}]});
147
        $("#arrow").rotateAnimation(0);                    
148
    } else {
149
        $("#arrow").rotate({animateAngle: (-180), bind:[{"click":function(){toggleMenu()}}]});
150
        $("#arrow").rotateAnimation(-180);
151
    }            
152
}
153

    
154
// confirmation overlay generation
155
function confirm_action(action_string, action_function, serverIDs, serverNames) {
156
    if (serverIDs.length == 1){
157
        $("#yes-no h3").text('You are about to ' + action_string + ' vm ' + serverNames[0]);
158
    } else if (serverIDs.length > 1){
159
        $("#yes-no h3").text('You are about to ' + action_string + ' ' + serverIDs.length + ' machines');
160
    } else {
161
        return false;
162
    }
163
    // action confirmation overlay
164
    var triggers = $("a#confirmation").overlay({
165
            // some mask tweaks suitable for modal dialogs
166
            mask: {
167
                    color: '#ebecff',
168
                    opacity: '0.9'
169
            },
170
        top: 'center',
171
        load: false
172
    });
173
    // yes or no?
174
    var buttons = $("#yes-no button").click(function(e) {
175
            // get user input
176
            var yes = buttons.index(this) === 0;
177
        //close the confirmation window
178
        $("a#confirmation").overlay().close(); 
179
        // return true=yes or false=no
180
        if (yes) {
181
            action_function(serverIDs);
182
        }
183
    });
184
    $("a#confirmation").data('overlay').load();
185
    return false;
186
}
187

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

    
239
// get and show a list of available standard and custom images
240
function update_images() { 
241
    $.ajax({
242
        url: '/api/v1.0/images/detail',
243
        type: "GET",
244
        //async: false,
245
        dataType: "json",
246
        timeout: TIMEOUT,
247
        error: function(jqXHR, textStatus, errorThrown) { 
248
                    ajax_error(jqXHR.status);
249
                    },
250
        success: function(data, textStatus, jqXHR) {
251
            try {
252
                                images = data.images;
253
                                update_wizard_images();
254
                        } catch(err){
255
                                ajax_error("NO_IMAGES");
256
                        }
257
        }
258
    });
259
    return false;
260
}
261

    
262
function update_wizard_images() {
263
        if ($("ul#standard-images li").toArray().length + $("ul#custom-images li").toArray().length == 0) {
264
                $.each(images, function(i,image){
265
                        var img = $('#image-template').clone().attr("id","img-"+image.id).fadeIn("slow");
266
                        img.find("label").attr('for',"img-radio-" + image.id);
267
                        img.find(".image-title").text(image.name);
268
                        img.find(".description").text(image.metadata.meta.key.description);
269
                        img.find(".size").text(image.size);
270
                        img.find("input.radio").attr('id',"img-radio-" + image.id);
271
                        if (i==0) img.find("input.radio").attr("checked","checked"); 
272
                        img.find("img.image-logo").attr('src','static/os_logos/'+image_tags[image.id]+'.png');
273
                        if (image.serverId) {
274
                                img.appendTo("ul#custom-images");
275
                        } else {
276
                                img.appendTo("ul#standard-images");
277
                        }
278
                });
279
        }        
280
}
281

    
282
function update_wizard_flavors(){
283
        // sliders for selecting VM flavor
284
        $("#cpu:range").rangeinput({min:0,
285
                                                           value:0,
286
                                                           step:1,
287
                                                           progress: true,
288
                                                           max:cpus.length-1});
289
        
290
        $("#storage:range").rangeinput({min:0,
291
                                                           value:0,
292
                                                           step:1,
293
                                                           progress: true,
294
                                                           max:disks.length-1});
295

    
296
        $("#ram:range").rangeinput({min:0,
297
                                                           value:0,
298
                                                           step:1,
299
                                                           progress: true,
300
                                                           max:ram.length-1});
301
        $("#small").click();
302
        
303
        // update the indicators when sliding
304
        $("#cpu:range").data().rangeinput.onSlide(function(event,value){
305
                $("#cpu-indicator")[0].value = cpus[Number(value)];
306
        });
307
        $("#cpu:range").data().rangeinput.change(function(event,value){
308
                $("#cpu-indicator")[0].value = cpus[Number(value)];                                
309
                $("#custom").click();                                
310
        });                        
311
        $("#ram:range").data().rangeinput.onSlide(function(event,value){
312
                $("#ram-indicator")[0].value = ram[Number(value)];
313
        });
314
        $("#ram:range").data().rangeinput.change(function(event,value){
315
                $("#ram-indicator")[0].value = ram[Number(value)];                                
316
                $("#custom").click();
317
        });                        
318
        $("#storage:range").data().rangeinput.onSlide(function(event,value){
319
                $("#storage-indicator")[0].value = disks[Number(value)];
320
        });
321
        $("#storage:range").data().rangeinput.change(function(event,value){
322
                $("#storage-indicator")[0].value = disks[Number(value)];                                
323
                $("#custom").click();
324
        });                                
325
}
326

    
327
Array.prototype.unique = function () {
328
        var r = new Array();
329
        o:for(var i = 0, n = this.length; i < n; i++)
330
        {
331
                for(var x = 0, y = r.length; x < y; x++)
332
                {
333
                        if(r[x]==this[i])
334
                        {
335
                                continue o;
336
                        }
337
                }
338
                r[r.length] = this[i];
339
        }
340
        return r;
341
}
342

    
343
// get and configure flavor selection
344
function update_flavors() { 
345
    $.ajax({
346
        url: '/api/v1.0/flavors/detail',
347
        type: "GET",
348
        //async: false,
349
        dataType: "json",
350
        timeout: TIMEOUT,
351
        error: function(jqXHR, textStatus, errorThrown) { 
352
            try {
353
                                ajax_error(jqXHR.status);
354
                        } catch (err) {
355
                                ajax_error(err);
356
                        }
357
        },
358
        success: function(data, textStatus, jqXHR) {
359
            flavors = data.flavors;
360
            $.each(flavors, function(i, flavor) {
361
                cpus[i] = flavor['cpu'];
362
                disks[i] = flavor['disk'];
363
                ram[i] = flavor['ram'];
364
            });
365
            cpus = cpus.unique();
366
            disks = disks.unique();
367
            ram = ram.unique();
368
                        update_wizard_flavors();
369
        }
370
    });
371
    return false;
372
}
373

    
374
// return flavorRef from cpu, disk, ram values
375
function identify_flavor(cpu, disk, ram){
376
    for (i=0;i<flavors.length;i++){
377
        if (flavors[i]['cpu'] == cpu && flavors[i]['disk']==disk && flavors[i]['ram']==ram) {
378
            return flavors[i]['id']
379
        }
380
    }
381
    return 0;
382
}
383

    
384
// update the actions in the 
385
function updateActions() {
386
        var states = [];
387
        var on = [];
388
        var checked = $("table.list-machines tbody input[type='checkbox']:checked");
389
        // disable all actions to begin with
390
        for (action in actions) {
391
                $("#action-" + action).removeClass('enabled');
392
        }
393

    
394
        // are there multiple machines selected?
395
        if (checked.length>1)
396
                states[0] = 'multiple';
397
        
398
        // check the states of selected machines
399
        checked.each(function(i,checkbox) {
400
                states[states.length] = checkbox.className;
401
                var ip = $("#" + checkbox.id.replace('input-','') + ".ip span.public").text();
402
                if (ip.replace('undefined','').length)
403
                        states[states.length] = 'network';
404
        });
405

    
406
        // decide which actions should be enabled
407
        for (a in actions) {
408
                var enabled = false;
409
                for (var s =0; s<states.length; s++) {
410
                        if (actions[a].indexOf(states[s]) != -1 ) {
411
                                enabled = true;
412
                        } else {
413
                                enabled = false;
414
                                break;
415
                        }
416
                }
417
                if (enabled)
418
                        on[on.length]=a;
419
        }
420
        // enable those actions
421
        for (action in on) {
422
                $("#action-" + on[action]).addClass('enabled');
423
        }
424
}
425

    
426
// reboot action
427
function reboot(serverIDs){
428
        if (!serverIDs.length){
429
                //ajax_success('DEFAULT');
430
                return false;
431
        }        
432
    // ajax post reboot call
433
    var payload = {
434
        "reboot": {"type" : "HARD"}
435
    };
436
    var serverID = serverIDs.pop();
437
        
438
        $.ajax({
439
                url: '/api/v1.0/servers/' + serverID + '/action',
440
                type: "POST",        
441
                dataType: "json",
442
                data: JSON.stringify(payload),
443
                timeout: TIMEOUT,
444
                error: function(jqXHR, textStatus, errorThrown) {
445
                    display_failure(serverID, jqXHR.status, 'Reboot')
446
                                },
447
                success: function(data, textStatus, jqXHR) {
448
                                        if ( jqXHR.status == '202') {
449
                        try {
450
                            console.info('rebooted ' + serverID);
451
                        } catch(err) {}
452
                                                // indicate that the action succeeded
453
                                                display_success(serverID);
454
                                                // continue with the rest of the servers
455
                                                reboot(serverIDs);
456
                                        } else {
457
                                                ajax_error(jqXHR.status);
458
                                        }
459
                                }
460
    });
461

    
462
    return false;
463
}
464

    
465
// shutdown action
466
function shutdown(serverIDs) {
467
        if (!serverIDs.length){
468
                //ajax_success('DEFAULT');
469
                return false;
470
        }
471
    // ajax post shutdown call
472
    var payload = {
473
        "shutdown": {"timeout" : "5"}
474
    };   
475

    
476
        var serverID = serverIDs.pop()
477
    $.ajax({
478
            url: '/api/v1.0/servers/' + serverID + '/action',
479
            type: "POST",
480
            dataType: "json",
481
        data: JSON.stringify(payload),
482
        timeout: TIMEOUT,
483
        error: function(jqXHR, textStatus, errorThrown) { 
484
                    display_failure(serverID, jqXHR.status, 'Shutdown')
485
                    },
486
        success: function(data, textStatus, jqXHR) {
487
                    if ( jqXHR.status == '202') {
488
                                                try {
489
                            console.info('suspended ' + serverID);
490
                        } catch(err) {}
491
                                                // indicate that the action succeeded
492
                                                display_success(serverID);
493
                                                // continue with the rest of the servers                        
494
                        shutdown(serverIDs);
495
                    } else {
496
                        ajax_error(jqXHR.status);
497
                    }
498
                }             
499
    });
500

    
501
    return false;    
502
}
503

    
504
// destroy action
505
function destroy(serverIDs) {
506
        if (!serverIDs.length){
507
                //ajax_success('DEFAULT');
508
                return false;
509
        }
510
    // ajax post destroy call can have an empty request body
511
    var payload = {};   
512

    
513
        serverID = serverIDs.pop()
514
    $.ajax({
515
            url: '/api/v1.0/servers/' + serverID,
516
            type: "DELETE",
517
            dataType: "json",
518
        data: JSON.stringify(payload),
519
        timeout: TIMEOUT,
520
        error: function(jqXHR, textStatus, errorThrown) { 
521
                    display_failure(serverID, jqXHR.status, 'Destroy')
522
                    },
523
        success: function(data, textStatus, jqXHR) {
524
                    if ( jqXHR.status == '202') {
525
                                                try {
526
                            console.info('destroyed ' + serverID);
527
                        } catch (err) {}
528
                                                // indicate that the action succeeded
529
                                                display_success(serverID);
530
                                                // continue with the rest of the servers
531
                        destroy(serverIDs);
532
                    } else {
533
                        ajax_error(jqXHR.status);
534
                    }
535
                }             
536
    });
537

    
538
    return false;    
539
}
540

    
541
// start action
542
function start(serverIDs){
543
        if (!serverIDs.length){
544
                //ajax_success('DEFAULT');
545
                return false;
546
        }        
547
    // ajax post start call
548
    var payload = {
549
        "start": {"type" : "NORMAL"}
550
    };   
551

    
552
        var serverID = serverIDs.pop()
553
    $.ajax({
554
        url: '/api/v1.0/servers/' + serverID + '/action',
555
        type: "POST",
556
        dataType: "json",
557
        data: JSON.stringify(payload),
558
        timeout: TIMEOUT,
559
        error: function(jqXHR, textStatus, errorThrown) { 
560
                    display_failure(serverID, jqXHR.status, 'Start')
561
                    },
562
        success: function(data, textStatus, jqXHR) {
563
                    if ( jqXHR.status == '202') {
564
                                            try {
565
                            console.info('started ' + serverID);
566
                        } catch(err) {}
567
                                                // indicate that the action succeeded
568
                                                display_success(serverID);
569
                                                // continue with the rest of the servers                                                
570
                        start(serverIDs);
571
                    } else {
572
                        ajax_error(jqXHR.status);
573
                    }
574
                }
575
    });
576

    
577
    return false;
578
}