Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ 0971fa71

History | View | Annotate | Download (17.3 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
function update_confirmations(){
19
    // hide all confirm boxes to begin with
20
    $('div.confirm_single').hide();
21
    $('div.confirm_multiple').hide();
22
   
23
        // standard view only
24
        if ($.cookie("list") != '1') { 
25
                for (i=0;i<pending_actions.length;i++){
26
            // show single confirms
27
                        $("div.machine#"+pending_actions[i][1]+' .confirm_single').show();        
28
                }                
29
        }
30

    
31
        // if more than one pending action show multiple confirm box
32
        if (pending_actions.length>1 || $.cookie("list") == '1' && pending_actions.length == 1){ 
33
                $('div.confirm_multiple span.actionLen').text(pending_actions.length);
34
                $('div.confirm_multiple').show();
35
        }
36
}
37

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

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

    
95
    return false;
96
}
97

    
98
function choose_view() {
99
    if ($.cookie("list")=='1') {
100
        list_view();
101
    } else {
102
        standard_view();
103
    }
104
}
105

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

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

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

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

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

    
276
function update_wizard_flavors(){
277
        // sliders for selecting VM flavor
278
        $("#cpu:range").rangeinput({min:0,
279
                                                           value:0,
280
                                                           step:1,
281
                                                           progress: true,
282
                                                           max:cpus.length-1});
283
        
284
        $("#storage:range").rangeinput({min:0,
285
                                                           value:0,
286
                                                           step:1,
287
                                                           progress: true,
288
                                                           max:disks.length-1});
289

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

    
321
Array.prototype.unique = function () {
322
        var r = new Array();
323
        o:for(var i = 0, n = this.length; i < n; i++)
324
        {
325
                for(var x = 0, y = r.length; x < y; x++)
326
                {
327
                        if(r[x]==this[i])
328
                        {
329
                                continue o;
330
                        }
331
                }
332
                r[r.length] = this[i];
333
        }
334
        return r;
335
}
336

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

    
368
// return flavorRef from cpu, disk, ram values
369
function identify_flavor(cpu, disk, ram){
370
    for (i=0;i<flavors.length;i++){
371
        if (flavors[i]['cpu'] == cpu && flavors[i]['disk']==disk && flavors[i]['ram']==ram) {
372
            return flavors[i]['id']
373
        }
374
    }
375
    return 0;
376
}
377

    
378
// update the actions in list view
379
function updateActions() {
380
        var states = [];
381
        var on = [];
382
        var checked = $("table.list-machines tbody input[type='checkbox']:checked");
383
        // disable all actions to begin with
384
        for (action in actions) {
385
                $("#action-" + action).removeClass('enabled');
386
        }
387

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

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

    
420
//create server action
421
function create_vm(machineName, imageRef, flavorRef){
422
    var payload = {
423
        "server": {
424
            "name": machineName,
425
            "imageRef": imageRef,
426
            "flavorRef" : flavorRef,
427
            "metadata" : {
428
                "My Server Name" : machineName
429
            },
430
        }
431
    };
432

    
433

    
434
    $.ajax({
435
    url: "/api/v1.0/servers",
436
    type: "POST",
437
    dataType: "json",    
438
    data: JSON.stringify(payload),
439
    timeout: TIMEOUT,
440
    error: function(jqXHR, textStatus, errorThrown) { 
441
                ajax_error(jqXHR.status);
442
           },
443
    success: function(data, textStatus, jqXHR) {
444
                if ( jqXHR.status == '202') {
445
                    ajax_success("CREATE_VM_SUCCESS", data.server.adminPass);                   
446
                } else {
447
                    ajax_error(jqXHR.status);
448
                }
449
            }
450
    });
451
}
452

    
453
// reboot action
454
function reboot(serverIDs){
455
        if (!serverIDs.length){
456
                //ajax_success('DEFAULT');
457
                return false;
458
        }        
459
    // ajax post reboot call
460
    var payload = {
461
        "reboot": {"type" : "HARD"}
462
    };
463
    var serverID = serverIDs.pop();
464
        
465
        $.ajax({
466
                url: API_URL + '/servers/' + serverID + '/action',
467
                type: "POST",        
468
                dataType: "json",
469
                data: JSON.stringify(payload),
470
                timeout: TIMEOUT,
471
                error: function(jqXHR, textStatus, errorThrown) {
472
                    display_failure(serverID, jqXHR.status, 'Reboot')
473
                                },
474
                success: function(data, textStatus, jqXHR) {
475
                                        if ( jqXHR.status == '202') {
476
                        try {
477
                            console.info('rebooted ' + serverID);
478
                        } catch(err) {}
479
                                                // indicate that the action succeeded
480
                                                display_success(serverID);
481
                                                // continue with the rest of the servers
482
                                                reboot(serverIDs);
483
                                        } else {
484
                                                ajax_error(jqXHR.status);
485
                                        }
486
                                }
487
    });
488

    
489
    return false;
490
}
491

    
492
// shutdown action
493
function shutdown(serverIDs) {
494
        if (!serverIDs.length){
495
                //ajax_success('DEFAULT');
496
                return false;
497
        }
498
    // ajax post shutdown call
499
    var payload = {
500
        "shutdown": {"timeout" : "5"}
501
    };   
502

    
503
        var serverID = serverIDs.pop()
504
    $.ajax({
505
            url: API_URL + '/servers/' + serverID + '/action',
506
            type: "POST",
507
            dataType: "json",
508
        data: JSON.stringify(payload),
509
        timeout: TIMEOUT,
510
        error: function(jqXHR, textStatus, errorThrown) { 
511
                    display_failure(serverID, jqXHR.status, 'Shutdown')
512
                    },
513
        success: function(data, textStatus, jqXHR) {
514
                    if ( jqXHR.status == '202') {
515
                                                try {
516
                            console.info('suspended ' + serverID);
517
                        } catch(err) {}
518
                                                // indicate that the action succeeded
519
                                                display_success(serverID);
520
                                                // continue with the rest of the servers                        
521
                        shutdown(serverIDs);
522
                    } else {
523
                        ajax_error(jqXHR.status);
524
                    }
525
                }             
526
    });
527

    
528
    return false;    
529
}
530

    
531
// destroy action
532
function destroy(serverIDs) {
533
        if (!serverIDs.length){
534
                //ajax_success('DEFAULT');
535
                return false;
536
        }
537
    // ajax post destroy call can have an empty request body
538
    var payload = {};   
539

    
540
        serverID = serverIDs.pop()
541
    $.ajax({
542
            url: API_URL + '/servers/' + serverID,
543
            type: "DELETE",
544
            dataType: "json",
545
        data: JSON.stringify(payload),
546
        timeout: TIMEOUT,
547
        error: function(jqXHR, textStatus, errorThrown) { 
548
                    display_failure(serverID, jqXHR.status, 'Destroy')
549
                    },
550
        success: function(data, textStatus, jqXHR) {
551
                    if ( jqXHR.status == '202') {
552
                                                try {
553
                            console.info('destroyed ' + serverID);
554
                        } catch (err) {}
555
                                                // indicate that the action succeeded
556
                                                display_success(serverID);
557
                                                // continue with the rest of the servers
558
                        destroy(serverIDs);
559
                    } else {
560
                        ajax_error(jqXHR.status);
561
                    }
562
                }             
563
    });
564

    
565
    return false;    
566
}
567

    
568
// start action
569
function start(serverIDs){
570
        if (!serverIDs.length){
571
                //ajax_success('DEFAULT');
572
                return false;
573
        }        
574
    // ajax post start call
575
    var payload = {
576
        "start": {"type" : "NORMAL"}
577
    };   
578

    
579
        var serverID = serverIDs.pop()
580
    $.ajax({
581
        url: API_URL + '/servers/' + serverID + '/action',
582
        type: "POST",
583
        dataType: "json",
584
        data: JSON.stringify(payload),
585
        timeout: TIMEOUT,
586
        error: function(jqXHR, textStatus, errorThrown) { 
587
                    display_failure(serverID, jqXHR.status, 'Start')
588
                    },
589
        success: function(data, textStatus, jqXHR) {
590
                    if ( jqXHR.status == '202') {
591
                                            try {
592
                            console.info('started ' + serverID);
593
                        } catch(err) {}
594
                                                // indicate that the action succeeded
595
                                                display_success(serverID);
596
                                                // continue with the rest of the servers                                                
597
                        start(serverIDs);
598
                    } else {
599
                        ajax_error(jqXHR.status);
600
                    }
601
                }
602
    });
603

    
604
    return false;
605
}