Statistics
| Branch: | Tag: | Revision:

root / ui / static / synnefo.js @ c5a032c4

History | View | Annotate | Download (15.2 kB)

1
var flavors = [], images = [], servers = [], disks = [], cpus = [], ram = [];
2
var changes_since = 0, deferred = 0, update_request = false;
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

    
18
function list_view() {
19
        changes_since = 0; // to reload full list
20
        clearTimeout(deferred);        // clear old deferred calls
21
        try {
22
                update_request.abort() // cancel pending ajax updates
23
        }catch(err){}
24
    $.cookie("list", '1'); // set list cookie
25
    $("div#machinesview").load($("#list").attr("href"), function(){
26
        $("a#standard")[0].className += ' activelink';
27
        $("a#list")[0].className = '';
28
    });
29
    return false;
30
}
31

    
32
function standard_view() {
33
        changes_since = 0; // to reload full list
34
        clearTimeout(deferred);        // clear old deferred calls
35
        try {
36
                update_request.abort() // cancel pending ajax updates
37
        }catch(err){}        
38
    $.cookie("list", '0');
39
    href=$("a#standard").attr("href");
40
    $("div#machinesview").load(href, function(){
41
        $("a#list")[0].className += ' activelink';
42
        $("a#standard")[0].className = '';
43
    });
44
    return false;
45
}
46

    
47
function choose_view() {
48
    if ($.cookie("list")=='1') {
49
        list_view();
50
    } else {
51
        standard_view();
52
    }
53
}
54

    
55
function toggleMenu() {
56
    var primary = $("ul.css-tabs li a.primary");
57
    var secondary = $("ul.css-tabs li a.secondary");
58
    var all = $("ul.css-tabs li a");                        
59
    var toggled = $('ul.css-tabs li a.current').hasClass('secondary');
60
    
61
    // if anything is still moving, do nothing
62
    if ($(":animated").length) {
63
        return;
64
    } 
65
    
66
    // nothing is current to begin with
67
    $('ul.css-tabs li a.current').removeClass('current');
68
    
69
    // move stuff around
70
    all.animate({top:'30px'}, {complete: function() { 
71
        $(this).hide();
72
        if (toggled) {
73
            primary.show();
74
            primary.animate({top:'9px'}, {complete: function() {
75
                $('ul.css-tabs li a.primary#machines').addClass('current');
76
                $('a#machines').click();                                   
77
            }});
78
        } else {
79
            secondary.show();
80
            secondary.animate({top:'9px'}, {complete: function() {
81
                $('ul.css-tabs li a.secondary#files').addClass('current');
82
                $('a#files').click();                                                                           
83
            }});
84
        }                                              
85
    }});
86
    
87
    // rotate arrow icon
88
    if (toggled) {
89
        $("#arrow").rotate({animateAngle: (0), bind:[{"click":function(){toggleMenu()}}]});
90
        $("#arrow").rotateAnimation(0);                    
91
    } else {
92
        $("#arrow").rotate({animateAngle: (-180), bind:[{"click":function(){toggleMenu()}}]});
93
        $("#arrow").rotateAnimation(-180);
94
    }            
95
}
96

    
97
// confirmation overlay generation
98
function confirm_action(action_string, action_function, serverIDs, serverNames) {
99
    if (serverIDs.length == 1){
100
        $("#yes-no h3").text('You are about to ' + action_string + ' vm ' + serverNames[0]);
101
    } else if (serverIDs.length > 1){
102
        $("#yes-no h3").text('You are about to ' + action_string + ' ' + serverIDs.length + ' machines');
103
    } else {
104
        return false;
105
    }
106
    // action confirmation overlay
107
    var triggers = $("a#confirmation").overlay({
108
            // some mask tweaks suitable for modal dialogs
109
            mask: {
110
                    color: '#ebecff',
111
                    opacity: '0.9'
112
            },
113
        top: 'center',
114
        load: false
115
    });
116
    // yes or no?
117
    var buttons = $("#yes-no button").click(function(e) {
118
            // get user input
119
            var yes = buttons.index(this) === 0;
120
        //close the confirmation window
121
        $("a#confirmation").overlay().close(); 
122
        // return true=yes or false=no
123
        if (yes) {
124
            action_function(serverIDs);
125
        }
126
    });
127
    $("a#confirmation").data('overlay').load();
128
    return false;
129
}
130

    
131
// get and show a list of running and terminated machines
132
function update_vms(interval) {
133
    try{ console.info('updating machines'); } catch(err){}
134
        var uri='/api/v1.0/servers/detail';
135
        
136
        if (changes_since != 0)
137
                uri+='?changes-since='+changes_since
138
                
139
    update_request = $.ajax({
140
        url: uri,
141
        type: "GET",
142
        timeout: TIMEOUT,
143
        dataType: "json",
144
        error: function(jqXHR, textStatus, errorThrown) {
145
                        // don't forget to try again later
146
                        if (interval) {
147
                                clearTimeout(deferred);        // clear old deferred calls
148
                                deferred = setTimeout(update_vms,interval,interval);
149
                        }
150
                        // as for now, just show an error message
151
                        try { console.info('update_vms errback:' + jqXHR.status ) } catch(err) {}
152
                        ajax_error();                                                
153
                        return false;
154
                        },
155
        success: function(data, textStatus, jqXHR) {
156
            changes_since_date = new Date(jqXHR.getResponseHeader('Date'));
157
            changes_since = ISODateString(changes_since_date);
158
                        if (interval) {
159
                                clearTimeout(deferred);        // clear old deferred calls
160
                                deferred = setTimeout(update_vms,interval,interval);
161
                        }
162
                        
163
                        if (jqXHR.status == 200 || jqXHR.status == 203) {
164
                                try {
165
                                        servers = data.servers;
166
                                } catch(err) { ajax_error('400');}
167
                                update_machines_view(data);
168
                        } else if (jqXHR.status != 304){
169
                                try { console.info('update_vms callback:' + jqXHR.status ) } catch(err) {}
170
                                //ajax_error();                                                
171
                        }
172
                        return false;
173
        }
174
    });
175
    return false;
176
}
177

    
178
// get and show a list of available standard and custom images
179
function update_images() { 
180
    $.ajax({
181
        url: '/api/v1.0/images/detail',
182
        type: "GET",
183
        //async: false,
184
        dataType: "json",
185
        timeout: TIMEOUT,
186
        error: function(jqXHR, textStatus, errorThrown) { 
187
                    ajax_error(jqXHR.status);
188
                    },
189
        success: function(data, textStatus, jqXHR) {
190
            try {
191
                                images = data.images;
192
                        } catch(err){
193
                                ajax_error("NO_IMAGES");
194
                        }
195
            if ($("ul#standard-images li").toArray().length + $("ul#custom-images li").toArray().length == 0) {
196
                $.each(data.images, function(i,image){
197
                    var img = $('#image-template').clone().attr("id","img-"+image.id).fadeIn("slow");
198
                    img.find("label").attr('for',"img-radio-" + image.id);
199
                    img.find(".image-title").text(image.name);
200
                    img.find(".description").text(image.metadata.meta.key.description);
201
                    img.find(".size").text(image.size);
202
                    img.find("input.radio").attr('id',"img-radio-" + image.id);
203
                    if (i==0) img.find("input.radio").attr("checked","checked"); 
204
                    img.find("img.image-logo").attr('src','static/os_logos/'+image_tags[image.id]+'.png');
205
                    if (image.serverId) {
206
                        img.appendTo("ul#custom-images");
207
                    } else {
208
                        img.appendTo("ul#standard-images");
209
                    }
210
                });
211
            }
212
        }
213
    });
214
    return false;
215
}
216

    
217
Array.prototype.unique = function () {
218
        var r = new Array();
219
        o:for(var i = 0, n = this.length; i < n; i++)
220
        {
221
                for(var x = 0, y = r.length; x < y; x++)
222
                {
223
                        if(r[x]==this[i])
224
                        {
225
                                continue o;
226
                        }
227
                }
228
                r[r.length] = this[i];
229
        }
230
        return r;
231
}
232

    
233
// get and configure flavor selection
234
function update_flavors() { 
235
    $.ajax({
236
        url: '/api/v1.0/flavors/detail',
237
        type: "GET",
238
        //async: false,
239
        dataType: "json",
240
        timeout: TIMEOUT,
241
        error: function(jqXHR, textStatus, errorThrown) { 
242
            try {
243
                                ajax_error(jqXHR.status);
244
                        } catch (err) {
245
                                ajax_error(err);
246
                        }
247
        },
248
        success: function(data, textStatus, jqXHR) {
249
            flavors = data.flavors;
250
            $.each(flavors, function(i, flavor) {
251
                cpus[i] = flavor['cpu'];
252
                disks[i] = flavor['disk'];
253
                ram[i] = flavor['ram'];
254
            });
255
            cpus = cpus.unique();
256
            disks = disks.unique();
257
            ram = ram.unique();
258
            // sliders for selecting VM flavor
259
            $("#cpu:range").rangeinput({min:0,
260
                                       value:0,
261
                                       step:1,
262
                                       progress: true,
263
                                       max:cpus.length-1});
264
            
265
            $("#storage:range").rangeinput({min:0,
266
                                       value:0,
267
                                       step:1,
268
                                       progress: true,
269
                                       max:disks.length-1});
270

    
271
            $("#ram:range").rangeinput({min:0,
272
                                       value:0,
273
                                       step:1,
274
                                       progress: true,
275
                                       max:ram.length-1});
276
            $("#small").click();
277
            
278
            // update the indicators when sliding
279
            $("#cpu:range").data().rangeinput.onSlide(function(event,value){
280
                $("#cpu-indicator")[0].value = cpus[Number(value)];
281
            });
282
            $("#cpu:range").data().rangeinput.change(function(event,value){
283
                $("#cpu-indicator")[0].value = cpus[Number(value)];                                
284
                $("#custom").click();                                
285
                        });                        
286
            $("#ram:range").data().rangeinput.onSlide(function(event,value){
287
                $("#ram-indicator")[0].value = ram[Number(value)];
288
            });
289
            $("#ram:range").data().rangeinput.change(function(event,value){
290
                $("#ram-indicator")[0].value = ram[Number(value)];                                
291
                $("#custom").click();
292
            });                        
293
            $("#storage:range").data().rangeinput.onSlide(function(event,value){
294
                $("#storage-indicator")[0].value = disks[Number(value)];
295
            });
296
            $("#storage:range").data().rangeinput.change(function(event,value){
297
                $("#storage-indicator")[0].value = disks[Number(value)];                                
298
                $("#custom").click();
299
            });                        
300
        }
301
    });
302
    return false;
303
}
304

    
305
// return flavorRef from cpu, disk, ram values
306
function identify_flavor(cpu, disk, ram){
307
    for (i=0;i<flavors.length;i++){
308
        if (flavors[i]['cpu'] == cpu && flavors[i]['disk']==disk && flavors[i]['ram']==ram) {
309
            return flavors[i]['id']
310
        }
311
    }
312
    return 0;
313
}
314

    
315
// update the actions in the 
316
function updateActions() {
317
        var states = [];
318
        var on = [];
319
        var checked = $("table.list-machines tbody input[type='checkbox']:checked");
320
        // disable all actions to begin with
321
        for (action in actions) {
322
                $("#action-" + action).removeClass('enabled');
323
        }
324

    
325
        // are there multiple machines selected?
326
        if (checked.length>1)
327
                states[0] = 'multiple';
328
        
329
        // check the states of selected machines
330
        checked.each(function(i,checkbox) {
331
                states[states.length] = checkbox.className;
332
                var ip = $("#" + checkbox.id.replace('input-','') + ".ip span.public").text();
333
                if (ip.replace('undefined','').length)
334
                        states[states.length] = 'network';
335
        });
336

    
337
        // decide which actions should be enabled
338
        for (a in actions) {
339
                var enabled = false;
340
                for (var s =0; s<states.length; s++) {
341
                        if (actions[a].indexOf(states[s]) != -1 ) {
342
                                enabled = true;
343
                        } else {
344
                                enabled = false;
345
                                break;
346
                        }
347
                }
348
                if (enabled)
349
                        on[on.length]=a;
350
        }
351
        // enable those actions
352
        for (action in on) {
353
                $("#action-" + on[action]).addClass('enabled');
354
        }
355
}
356

    
357
// reboot action
358
function reboot(serverIDs){
359
        if (!serverIDs.length){
360
                ajax_success('DEFAULT');
361
                return false;
362
        }        
363
    // ajax post reboot call
364
    var payload = {
365
        "reboot": {"type" : "HARD"}
366
    };
367
    serverID = serverIDs.pop();
368
        
369
        $.ajax({
370
                url: '/api/v1.0/servers/' + serverID + '/action',
371
                type: "POST",        
372
                dataType: "json",
373
                data: JSON.stringify(payload),
374
                timeout: TIMEOUT,
375
                error: function(jqXHR, textStatus, errorThrown) {
376
                                        ajax_error(jqXHR.status);
377
                                },
378
                success: function(data, textStatus, jqXHR) {
379
                                        if ( jqXHR.status == '202') {
380
                        try {
381
                            console.info('rebooted ' + serverID);
382
                        } catch(err) {}                   
383
                                                reboot(serverIDs);
384
                                        } else {
385
                                                ajax_error(jqXHR.status);
386
                                        }
387
                                }
388
    });
389

    
390
    return false;
391
}
392

    
393
// shutdown action
394
function shutdown(serverIDs) {
395
        if (!serverIDs.length){
396
                ajax_success('DEFAULT');
397
                return false;
398
        }
399
    // ajax post shutdown call
400
    var payload = {
401
        "shutdown": {"timeout" : "5"}
402
    };   
403

    
404
        serverID = serverIDs.pop()
405
    $.ajax({
406
            url: '/api/v1.0/servers/' + serverID + '/action',
407
            type: "POST",
408
            dataType: "json",
409
        data: JSON.stringify(payload),
410
        timeout: TIMEOUT,
411
        error: function(jqXHR, textStatus, errorThrown) { 
412
                    ajax_error(jqXHR.status);
413
                    },
414
        success: function(data, textStatus, jqXHR) {
415
                    if ( jqXHR.status == '202') {
416
                                                try {
417
                            console.info('suspended ' + serverID);
418
                        } catch(err) {}                                       
419
                        shutdown(serverIDs);
420
                    } else {
421
                        ajax_error(jqXHR.status);
422
                    }
423
                }             
424
    });
425

    
426
    return false;    
427
}
428

    
429
// destroy action
430
function destroy(serverIDs) {
431
        if (!serverIDs.length){
432
                ajax_success('DEFAULT');
433
                return false;
434
        }
435
    // ajax post destroy call can have an empty request body
436
    var payload = {};   
437

    
438
        serverID = serverIDs.pop()
439
    $.ajax({
440
            url: '/api/v1.0/servers/' + serverID,
441
            type: "DELETE",
442
            dataType: "json",
443
        data: JSON.stringify(payload),
444
        timeout: TIMEOUT,
445
        error: function(jqXHR, textStatus, errorThrown) { 
446
                    ajax_error(jqXHR.status);
447
                    },
448
        success: function(data, textStatus, jqXHR) {
449
                    if ( jqXHR.status == '202') {
450
                                                try {
451
                            console.info('destroyed ' + serverID);
452
                        } catch (err) {}                                        
453
                        destroy(serverIDs);
454
                    } else {
455
                        ajax_error(jqXHR.status);
456
                    }
457
                }             
458
    });
459

    
460
    return false;    
461
}
462

    
463
// start action
464
function start(serverIDs){
465
        if (!serverIDs.length){
466
                ajax_success('DEFAULT');
467
                return false;
468
        }        
469
    // ajax post start call
470
    var payload = {
471
        "start": {"type" : "NORMAL"}
472
    };   
473

    
474
        serverID = serverIDs.pop()
475
    $.ajax({
476
        url: '/api/v1.0/servers/' + serverID + '/action',
477
        type: "POST",
478
        dataType: "json",
479
        data: JSON.stringify(payload),
480
        timeout: TIMEOUT,
481
        error: function(jqXHR, textStatus, errorThrown) { 
482
                    ajax_error(jqXHR.status);
483
                    },
484
        success: function(data, textStatus, jqXHR) {
485
                    if ( jqXHR.status == '202') {
486
                                            try {
487
                            console.info('started ' + serverID);
488
                        } catch(err) {}                      
489
                        start(serverIDs);
490
                    } else {
491
                        ajax_error(jqXHR.status);
492
                    }
493
                }
494
    });
495

    
496
    return false;
497
}