Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines_icon.html @ 4529511c

History | View | Annotate | Download (41.4 kB)

1
<!--
2
Copyright 2011 GRNET S.A. All rights reserved.
3

4
Redistribution and use in source and binary forms, with or
5
without modification, are permitted provided that the following
6
conditions are met:
7

8
  1. Redistributions of source code must retain the above
9
     copyright notice, this list of conditions and the following
10
     disclaimer.
11

12
  2. Redistributions in binary form must reproduce the above
13
     copyright notice, this list of conditions and the following
14
     disclaimer in the documentation and/or other materials
15
     provided with the distribution.
16

17
THIS SOFTWARE IS PROVIDED BY GRNET S.A. ``AS IS'' AND ANY EXPRESS
18
OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GRNET S.A OR
21
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
24
USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
25
AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26
LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
27
ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28
POSSIBILITY OF SUCH DAMAGE.
29

30
The views and conclusions contained in the software and
31
documentation are those of the authors and should not be
32
interpreted as representing official policies, either expressed
33
or implied, of GRNET S.A.
34
-->
35

    
36
{% load i18n %}
37

    
38
<!-- the standard view -->
39
<div id="machinesview-icon" class="standard">
40
    <div class="machine-container" id="machine-container-template" style="display:none">
41
        <div class="machine" id="machine-template">
42
            <div class='connect-border' title='{% trans 'Connect  machine' %}'></div>
43
            <div class='connect-arrow' title='{% trans 'Connect  machine' %}'></div>
44
            <div class="logo"></div>
45
            <div class="machine-details">
46
                <div href="#" class="name">
47
                    <h5 class="namecontainer editable">
48
                        <span class="name">node.name</span><span class="rename"></span>
49
                        <div class="editbuttons" style="display:none">
50
                            <div class="save"></div>
51
                            <div class="cancel"></div>
52
                        </div>
53
                    </h5>
54
                </div>
55
                <span class="ip">
56
                    <h5>
57
                        {% trans "IP:" %} <span class="ip-version-label">v4</span> <span class="public ipv4-text"></span>
58
                        <span class="ip-version-label">v6</span> <span class="public ipv6-text"></span>
59
                    </h5>
60
                </span>
61
            </div>
62
            <div class="info">
63
                <div class="info-header">
64
                    <div class="info-label">{% trans "info" %}</div>
65
                    <div class="toggler down"></div>
66
                </div>
67
            </div>
68
            <div class="info-content">
69
                <div class="metadata-container">
70
                    <div class="vm-details metadata-column">
71
                        {% trans "CPUs" %}: <span class="cpu-data">1</span><br />
72
                        {% trans "RAM" %}: <span class="ram-data">2048</span>MB<br />
73
                        {% trans "System Disk" %}: <span class="disk-data">20</span>GB <br /><br />
74
                        {% trans "Image" %}: <span class="image-data">Debian</span><br />
75
                        {% trans "Image Size" %}: <span class="image-size-data">2.3</span>MB
76
                    </div>
77
                    <div class="vm-stats metadata-column">
78
                        <div class='stat-label'>{% trans "CPU" %}</div>
79
                        <div class='stat-content cpu-cont'>
80
                            <img src="./static/icons/indicators/small/progress.gif" class="cpu bar" />
81
                            <img src="./static/icons/indicators/small/progress.gif" class="stat-busy" />
82
                            <div class='stat-error'>{% trans "Could not fetch CPU stats graph." %}</div>
83
                        </div>
84
                        <div class='stat-label'>{% trans "Net" %}</div>
85
                        <div class='stat-content net-cont'>
86
                            <img src="./static/icons/indicators/small/progress.gif" class="net bar" />
87
                            <img src="./static/icons/indicators/small/progress.gif" class="stat-busy" />
88
                            <div class='stat-error'>{% trans "Could not fetch Net stats graph." %}</div>
89
                        </div>
90
                        <a href="#" class="stats-report">{% trans "Full report" %}</a>
91
                    </div>
92
                    <div class="vm-metadata metadata-column">
93
                        <div class="metadata-left">
94
                            {% trans "Tags" %}: <br />
95
                            (<span class="metadata-count">0</span>)
96
                        </div>
97
                        <div class="metadata-keys-container">
98
                            <div class="scrollable vertical">
99
                                <div class="items">
100
                                </div>
101
                            </div>
102
                            <div class="metadata-actions">
103
                                <div class="prev"></div>
104
                                <div class="next"></div>
105
                            </div>
106
                        </div>
107
                        <a href="#" class="manage-metadata">{% trans "Manage Tags" %}</a>
108
                    </div>
109
                </div>
110
            </div>
111
            <div class="state">
112
                <div class="status">{% trans "Running" %}</div>
113
                <div class="indicators">
114
                    <div class="indicator1"></div>
115
                    <div class="indicator2"></div>
116
                    <div class="indicator3"></div>
117
                    <div class="indicator4"></div>
118
                </div>
119
                <div class="action-indicator" style="display:none"></div>
120
                <img class="spinner" style="display:none" src="static/icons/indicators/medium/progress.gif" />
121
                <img class="wave" style="display:none" src="static/icons/indicators/medium/wave.gif" />
122
            </div>
123
            <div class="actions clearfix">
124
                <div class="action-container start">
125
                    <a href="#" class="action-start">{% trans "Start" %}</a>
126
                    <div class="confirm_single">
127
                        <button class="yes">{% trans "Confirm" %}</button>
128
                        <button class="no">X</button>
129
                    </div>
130
                </div>
131
                <div class="action-container reboot">
132
                    <a href="#" class="action-reboot">{% trans "Reboot" %}</a>
133
                    <div class="confirm_single">
134
                        <button class="yes">{% trans "Confirm" %}</button>
135
                        <button class="no">X</button>
136
                    </div>
137
                </div>
138
                <div class="action-container shutdown">
139
                    <a href="#" class="action-shutdown">{% trans "Shutdown" %}</a>
140
                    <div class="confirm_single">
141
                        <button class="yes">{% trans "Confirm" %}</button>
142
                        <button class="no">X</button>
143
                    </div>
144
                </div>
145
                <div class="action-container console">
146
                    <a href="#" class="action-console">{% trans "Console" %}</a>
147
                    <div class="confirm_single">
148
                        <button class="yes">{% trans "Confirm" %}</button>
149
                        <button class="no">X</button>
150
                    </div>
151
                </div>
152
                <div class="action-container destroy">
153
                    <a href="#" class="action-destroy">{% trans "Destroy" %}</a>
154
                    <div class="confirm_single">
155
                        <button class="yes">{% trans "Confirm" %}</button>
156
                        <button class="no">X</button>
157
                    </div>
158
                </div>
159
            </div>
160
            <div class="action_error" align="center">
161
                {% trans "<span>Error</span> on" %} <span class="action">{% trans "error action" %}</span>
162
                <span class="code"></span>
163
                <span class="message"></span>
164
                <button class="details">{% trans "Details" %}</button>
165
            </div>
166
        </div>
167
        <div class="separator"></div>
168
    </div><div class="large-spinner"></div>
169
    <div class="running disabled"></div>
170
    <div class="terminated" style="display:none;"></div>
171
</div>
172

    
173
<script>
174
CONFIRMBOX_OFFSET = 200;
175

176
init_action_indicator_handlers('icon');
177

178
// handle connect machine image states
179
$("div.connect-arrow, div.running .machine .logo").live('mouseover',
180
    function() {
181
        if ($(this).parent().parent().find('.status').text().replace(TRANSITION_STATE_APPEND, "") != STATUSES['ACTIVE']) { return };
182
        set_machine_os_image($(this).parent().parent(), "icon", "hover", undefined, 1);
183
        var parent = $(this).parent().parent();
184
        parent.find(".connect-arrow").show().addClass('border-hover');
185
    });
186

187
$("div.connect-arrow, div.running .machine .logo").live('mouseleave',
188
    function() {
189
        if ($(this).parent().parent().find('.status').text().replace(TRANSITION_STATE_APPEND, "") != STATUSES['ACTIVE']) { return };
190
        set_machine_os_image($(this).parent().parent(), "icon", "hover", undefined, 1, "hover");
191
        // mouseup outside the element is not fired
192
        set_machine_os_image($(this).parent().parent(), "icon", "hover", undefined, 1, "click");
193
        var parent = $(this).parent().parent();
194
        parent.find(".connect-arrow").show().removeClass('border-hover');
195
    });
196

197
$("div.connect-arrow, div.running .machine .logo").live('mousedown',
198
function() {
199
        if ($(this).parent().parent().find(".connect-arrow:visible").length == 0) { return };
200
        set_machine_os_image($(this).parent().parent(), "icon", "click", undefined, 1);
201
    });
202

203
$("div.connect-arrow, div.running .machine .logo").live('mouseup',
204
    function() {
205
        if ($(this).parent().parent().find(".connect-arrow:visible").length == 0) { return };
206
        set_machine_os_image($(this).parent().parent(), "icon", "click", undefined, 1, "click");
207
    });
208

209
// actions on machine mouseover
210
$("#machinesview-icon.standard .machine").live('mouseover', function() {
211
    // show connect button only if the machine is active
212
    if ($(this).find('.status').text().replace(TRANSITION_STATE_APPEND, "") == STATUSES['ACTIVE']) {
213
        $(this).find("div.connect-arrow").show();
214
        $(this).find("div.connect-border").show();
215
    }
216
});
217

218
// actions on machine mouseout
219
$("#machinesview-icon.standard .machine").live('mouseout', function() {
220
    // hide connect button
221
    $(this).find("div.connect-arrow").hide();
222
    $(this).find("div.connect-border").hide();
223
});
224

225
// actions on connect arrow border mouseover
226
$("#machinesview-icon.standard .running div.connect-border").live('mouseover', function() {
227
    $(this).next().addClass('border-hover');
228
});
229

230
// actions on connect arrow border mouseout
231
$("#machinesview-icon.standard .running div.connect-border").live('mouseout', function() {
232
    $(this).next().removeClass('border-hover');
233
});
234

235
// open console on machine logo click
236
$("#machinesview-icon.standard .running div.logo").live('click', function(){
237
    if ($(this).parent().parent().find(".connect-arrow:visible").length == 0) { return };
238
    var serverID = $(this).parent().parent().attr("id");
239
    machine_connect([machine_connect, serverID]);
240
    return false;
241
});
242

243
$("#machinesview-icon.standard .running div.connect-arrow").live('click', function(){
244
    var serverID = $(this).parent().parent().attr("id");
245
    machine_connect([machine_connect, serverID]);
246
    return false;
247
});
248

249
// open console on connect arrow border click
250
$("#machinesview-icon.standard .running div.connect-border").live('click', function(){
251
    var serverID = $(this).parent().parent().attr("id");
252
    machine_connect([machine_connect, serverID]);
253
    return false;
254
});
255

256
//hide the all of the info contents
257
$("#machinesview-icon.standard .info-content").hide();
258
//toggle the component with class info-content
259
$("#machinesview-icon.standard div.info-header").live('click', function() {
260
    if ($(this).find('.toggler').hasClass('up')) {
261
        // toggle drop-down pane
262
        $(this).find('.toggler').removeClass('up');
263
        $(this).find('.toggler').addClass('down');
264
        $(this).find('.info-label').removeClass('darker');
265
        $(this).parent().parent().removeClass('light-background');
266
    } else {
267
        // reset stats
268
        $(this).closest('.machine-container').find('.vm-stats div.stat-error').hide();
269
        $(this).closest('.machine-container').find('.vm-stats img.cpu').attr('src', './static/icons/indicators/small/progress.gif').show();
270
        $(this).closest('.machine-container').find('.vm-stats img.net').attr('src', './static/icons/indicators/small/progress.gif').show();
271
        // get new stats
272
        var serverID = $(this).closest('.machine-container').attr('id');
273
        get_server_stats(serverID);
274
        // toggle drop-down pane
275
        $(this).find('.toggler').removeClass('down');
276
        $(this).find('.toggler').addClass('up');
277
        $(this).find('.info-label').addClass('darker');
278
        $(this).parent().parent().addClass('light-background');
279
    }
280
    $(this).parent().parent().find(".info-content").slideToggle(600);
281
    return false;
282
});
283

284

285
// intercept manage metadata click
286
$("#machinesview-icon.standard a.manage-metadata").live('click', function() {
287
    // get server name and server ID
288
    var serverID = $(this).closest('.machine-container').attr("id");
289
    var serverName = $(this).closest('.machine').find("span.name").text();
290
    // set server name to all related metadata dialogs
291
    $("#metadata-wizard div.machine-name").text(serverName);
292
    if ($(this).closest('.machine-container').parent().hasClass('terminated')) {
293
        $("#metadata-wizard div#on-off").text('off');
294
    } else {
295
        $("#metadata-wizard div#on-off").text('on');
296
    }
297
    // set server id to all related metadata dialogs
298
    $("#metadata-wizard p").text(serverID);
299
    show_metadata_wizard();
300
    return false;
301
});
302

303
//initiate machine renaming
304
$("#machinesview-icon.standard .rename, #machinesview-icon.standard h5.editable span.name").live('click', function() {
305
    serverId = $(this).closest('.machine-container').attr("id");
306
    vm = get_machine(serverId);
307

308
    $(this).parent().find('.name').html("<input type=\"text\" class=\"nametextbox\" value=\"" +
309
                                        vm.name +
310
                                        "\" / ><span class=\"oldValue\">" +
311
                                        vm.name + "</span>");
312
    $(this).parent().find('.rename').hide();
313
    $(this).parent().find(".editbuttons").fadeIn();
314
    $(this).parent().find(".nametextbox").focus().select();
315
    $(this).parent().removeClass('editable');
316

317
    //submit wizard by pressing enter on the name textbox
318
    $(".nametextbox").keydown(function (e) {
319
        if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
320
            $(this).parent().parent().find('div.editbuttons div.save').click();
321
            return false;
322
        } else if ((e.which && e.which == 27) || (e.keyCode && e.keyCode == 27)) {
323
            $(this).parent().parent().find('div.editbuttons div.cancel').click();
324
            return true;
325
        }
326
    });
327
    return false;
328
});
329

330
//rename machine
331
$("#machinesview-icon.standard .editbuttons .save").live('click', function() {
332
    serverID = $(this).closest('.machine-container').attr("id");
333
    serverName = $(this).parent().parent().find('.name').find('.nametextbox').val();
334
    if (serverName.trim() == ''){
335
        return false;
336
    }
337

338
    vm = get_machine(serverId)
339
    vm.name = serverName;
340
    longName = vm.name;
341

342
    var serverName = $(this).parent().parent().find('.nametextbox').val();
343
    serverName = fix_server_name(serverName);
344

345
    $(this).parent().parent().find('.name').html(serverName);
346
    $(this).parent().parent().find(".editbuttons").fadeOut("fast");
347
    $(this).parent().parent().find(".rename").fadeIn("slow");
348
    $(this).parent().parent().addClass('editable');
349
    rename(serverID, longName);
350
    return false;
351
});
352

353
//cancel renaming
354
$("#machinesview-icon.standard .editbuttons .cancel").live('click', function() {
355
    $(this).parent().parent().find('.name').html(fix_server_name($(this).parent().parent().find('.oldValue').text()));
356
    $(this).parent().parent().find(".editbuttons").hide();
357
    $(this).parent().parent().find(".rename").fadeIn();
358
    $(this).parent().parent().addClass('editable');
359
    return false;
360
});
361

362
// intercept reboot click
363
$("#machinesview-icon.standard div.actions a.action-reboot").live('click', function() {
364
    // get server id and server name from DOM
365
    var serverID = $(this).closest("div.machine-container").attr("id");
366
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
367
    var found = false;
368
    // show/hide proper menus
369
    $(this).parent().parent().find('a').removeClass('selected');
370
    $(this).addClass('selected');
371
    $(this).parent().parent().addClass('display');
372
    $(this).closest("div.machine").find('.action_error').hide();
373
    // if there is already a pending action for this server replace it
374
    for (i=0; i<pending_actions.length; i++) {
375
        if (pending_actions[i][1] == serverID) {
376
            pending_actions[i][0] = reboot;
377
            found = true
378
        }
379
    }
380
    // no pending action for this server was found, so let's just add it to the list
381
    if (!found)
382
        pending_actions.push([reboot, serverID, serverName])
383
    // pass the proper action to update confirmation boxes
384
    update_confirmations();
385
    return false;
386
});
387

388
// intercept shutdown click
389
$("#machinesview-icon.standard div.actions a.action-shutdown").live('click', function() {
390
    // get server id and server name from DOM
391
    var serverID = $(this).closest("div.machine-container").attr("id");
392
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
393
    var found = false;
394
    // show/hide proper menus
395
    $(this).parent().parent().find('a').removeClass('selected');
396
    $(this).addClass('selected');
397
    $(this).parent().parent().addClass('display');
398
    $(this).closest("div.machine").find('.action_error').hide();
399
    // if there is already a pending action for this server replace it
400
    for (i=0; i<pending_actions.length; i++) {
401
        if (pending_actions[i][1] == serverID) {
402
            pending_actions[i][0] = shutdown;
403
            found = true
404
        }
405
    }
406
    // no pending action for this server was found, so let's just add it to the list
407
    if (!found)
408
        pending_actions.push([shutdown, serverID, serverName])
409
    update_confirmations();
410
    return false;
411
});
412

413
// intercept start click
414
$("#machinesview-icon.standard div.actions a.action-start").live('click', function() {
415
    // get server id and server name from DOM
416
    var serverID = $(this).closest("div.machine-container").attr("id");
417
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
418
    var found = false;
419
    // show/hide proper menus
420
    $(this).parent().parent().find('a').removeClass('selected');
421
    $(this).addClass('selected');
422
    $(this).parent().parent().addClass('display');
423
    $(this).closest("div.machine").find('.action_error').hide();
424
    // if there is already a pending action for this server replace it
425
    for (i=0; i<pending_actions.length; i++) {
426
        if (pending_actions[i][1] == serverID) {
427
            pending_actions[i][0] = start;
428
            found = true
429
        }
430
    }
431
    // no pending action for this server was found, so let's just add it to the list
432
    if (!found)
433
        pending_actions.push([start, serverID, serverName])
434
    update_confirmations();
435
    return false;
436
});
437

438
// intercept console click
439
$("#machinesview-icon.standard div.actions a.action-console").live('click', function() {
440
    // get server id and server name from DOM
441
    var serverID = $(this).closest("div.machine-container").attr("id");
442
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
443
    var found = false;
444
    // show/hide proper menus
445
    $(this).parent().parent().find('a').removeClass('selected');
446
    $(this).addClass('selected');
447
    $(this).parent().parent().addClass('display');
448
    $(this).closest("div.machine").find('.action_error').hide();
449
    // if there is already a pending action for this server replace it
450
    for (i=0; i<pending_actions.length; i++) {
451
        if (pending_actions[i][1] == serverID) {
452
            pending_actions[i][0] = open_console;
453
            found = true
454
        }
455
    }
456
    // no pending action for this server was found, so let's just add it to the list
457
    if (!found)
458
        pending_actions.push([open_console, serverID, serverName])
459
    update_confirmations();
460
    return false;
461
});
462

463

464
// intercept destroy click
465
$("#machinesview-icon.standard div.actions a.action-destroy").live('click', function() {
466
    // get server id and server name from DOM
467
    var serverID = $(this).closest("div.machine-container").attr("id");
468
    var serverName = $(this).closest("div.machine").find("div.name span.name").text();
469
    var found = false;
470
    // show/hide proper menus
471
    $(this).parent().parent().find('a').removeClass('selected');
472
    $(this).addClass('selected');
473
    $(this).parent().parent().addClass('display');
474
    $(this).closest("div.machine").find('.action_error').hide();
475
    // if there is already a pending action for this server replace it
476
    for (i=0; i<pending_actions.length; i++) {
477
        if (pending_actions[i][1] == serverID) {
478
            pending_actions[i][0] = destroy;
479
            found = true
480
        }
481
    }
482
    // no pending action for this server was found, so let's just add it to the list
483
    if (!found)
484
        pending_actions.push([destroy, serverID, serverName])
485
    update_confirmations();
486
    return false;
487
});
488

489
$("#machinesview-icon.standard div.confirm_single button.yes").live('click', function(){
490
    var serverID = $(this).closest("div.machine-container").attr("id");
491
    // if there is a pending action for this server execute it
492
    for (i=0; i<pending_actions.length; i++) {
493
        if (pending_actions[i][1]==serverID){
494
            action = pending_actions.splice(i,1)[0]; // extract action
495
            // change the status text in cases where no api state exists
496
            if (action[0] == start) {
497
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Starting']);
498
                $(this).closest("div.machine").find('.state').removeClass().addClass('state starting-state');
499
                $(this).closest("div.machine").find('.spinner').show();
500
            } else if (action[0] == shutdown) {
501
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Shutting down']);
502
                $(this).closest("div.machine").find('.state').removeClass().addClass('state shutting-state');
503
                $(this).closest("div.machine").find('.spinner').show();
504
            } else if (action[0] == reboot) {
505
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Rebooting']);
506
                $(this).closest("div.machine").find('.state').removeClass().addClass('state rebooting-state');
507
                $(this).closest("div.machine").find('.spinner').show();
508
            }  else if (action[0] == destroy) {
509
                $(this).closest("div.machine").find('.status').text(TRANSITIONS['Destroying']);
510
                $(this).closest("div.machine").find('.state').removeClass().addClass('state destroying-state');
511
                $(this).closest("div.machine").find('.spinner').show();
512
            }
513
            action[0]([action[1]]); // execute action
514
        }
515
    }
516

517
    $(this).parent().hide();
518
    $(this).closest('div.actions').find('a').removeClass('selected');
519
    $(this).closest("div.machine").children('.state').children('.spinner').show()
520
    $(this).closest("div.machine").children('div.actions').removeClass('display');
521
    update_transition_names();
522
    update_confirmations();
523
    return false;
524
});
525

526
$("#machinesview-icon.standard div.confirm_single button.no").live('click', function(){
527
    // remove the action from the pending list
528
    var serverID = $(this).closest("div.machine-container").attr("id");
529

530
    $(this).closest('div.action-container').children('a').removeClass('selected');
531
    $(this).closest('div.actions').removeClass('display');
532
    for (i=0; i<pending_actions.length; i++) { // if there is a pending action for this server remove it
533
        if (pending_actions[i][1] == serverID) {
534
            pending_actions.splice(i,1);
535
        }
536
    }
537
    $(this).parent().hide();
538
    update_confirmations();
539
    return false;
540
});
541

542
$("#machinesview-icon.standard div.action_error .details").live('click', function(){
543
    // remove the action from the pending list
544
    ajax_error($(this).parent().children('.code').text(), undefined, $(this).parent().children('.action').text(), $(this).parent().children('.message').text());
545
    $(this).parent().hide();
546
});
547

548
// update the servers list
549
function update_machines_view(data) {
550
    /*
551
    Go through the servers in the input data. Update existing entries, add
552
    new ones to the list
553
    */
554
    $.each(data.servers.values, function(i,server) {
555

556
        // get DOM element, if it exists
557
        existing = $('#machinesview-icon.standard #' + server.id);
558
        // get server OS, if it exists
559
        if (!(server.metadata == undefined)) {
560
            var server_image = os_icon(server.metadata);
561
        } else {
562
            var server_image = "unknown"
563
        }
564
        // get server status message, if it exists
565
        var current_message = existing.find(".status").text().replace(TRANSITION_STATE_APPEND,"");
566
        // if multiple machines exist in the DOM, delete all but one
567
        // defensive coding - that shouldn't happen normally
568
        while (existing.length > 1){
569
            existing.remove();
570
        }
571
        // if server already exists in DOM, update its values
572
        if (existing.length){
573
            //  if the status is deleted
574
            if (server.status == 'DELETED') {
575
                // delete server entry from the DOM
576
                log_server_status_change(existing, 'DELETED');
577
                existing.remove();
578
            }
579
            // if the status has changed
580
            else if ( current_message != STATUSES[server.status]) {
581
                /*
582
                Here there are 4 possibilities:
583
                    1. From an active state to an inactive one
584
                    2. From an inactive state to an active one
585
                    3. From an active state to a different active one
586
                    4. From an inactive state to a different inactive one
587
                The last two (3, 4) can be dealt with the same way
588
                */
589
                if (ACTIVE_STATES.indexOf(current_message) >= 0 &&
590
                    INACTIVE_STATES.indexOf(STATUSES[server.status]) >= 0) {
591
                    // from an active state to an inactive one
592
                    log_server_status_change(existing, server.status);
593
                    moved = existing.clone().appendTo("#machinesview-icon.standard .terminated");
594
                    set_machine_os_image(moved, "icon", "off", server_image);
595
                    existing.remove();
596
                    existing = moved;
597
                    existing.find(".status").text(STATUSES[server.status]);
598
                    existing.find('.spinner').hide();
599
                    if ($("div.terminated").find("div.machine-container").length > 0) {
600
                        $("div.terminated").show();
601
                    }
602
                    existing.find(' .wave').attr('src','static/icons/indicators/medium/wave.gif').show();
603
                    existing.find('.state').removeClass().addClass('state terminated-state');
604
                    setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
605
                }
606
                else if (INACTIVE_STATES.indexOf(current_message) >= 0 &&
607
                         ACTIVE_STATES.indexOf(STATUSES[server.status]) >= 0) {
608
                    // From an inactive state to an active one
609
                    log_server_status_change(existing, server.status);
610
                    moved = existing.clone().appendTo("#machinesview-icon.standard .running");
611
                    set_machine_os_image(moved, "icon", "on", server_image);
612
                    existing.remove();
613
                    existing = moved;
614
                    existing.find(".status").text(STATUSES[server.status]);
615
                    existing.find('.spinner').hide();
616
                    if ($("div.terminated").find("div.machine-container").length == 0) {
617
                        $("div.terminated").hide();
618
                    }
619
                    existing.find(' .wave').attr('src','static/icons/indicators/medium/wave.gif').show();
620
                    existing.find('.state').removeClass().addClass('state running-state');
621
                    setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
622
                }
623
                else {
624
                    // handling active to active or inactive to inactive changes
625
                    if (TRANSITIONS[current_message] && TRANSITIONS[current_message] != 'Rebooting') {
626
                        // don't do anything if it is still in transition
627
                    }
628
                    else if ((TRANSITIONS[current_message] == 'Rebooting' && server.status == 'ACTIVE') ||
629
                             (STATUSES['BUILD'] == current_message && server.status == 'ACTIVE')) {
630
                        // if it has been rebooted or just created
631
                        log_server_status_change(existing, server.status);
632
                        existing.find(".status").text(STATUSES[server.status]);
633
                        existing.find('.spinner').hide();
634
                        existing.find(' .wave').attr('src','static/icons/indicators/medium/wave.gif').show();
635
                        existing.find('.state').removeClass().addClass('state running-state');
636
                        setTimeout("$('#" + server.id +" .wave').attr('src','').hide()", 3000);
637
                    }
638
                    else if (STATUSES[server.status] == "Rebooting") { 
639
                        // from running to rebooting
640
                        log_server_status_change(existing, server.status);
641
                        existing.find(".state").removeClass().addClass('state rebooting-state');
642
                        existing.find('.spinner').show();
643
                        existing.find(".status").text(STATUSES[server.status]);
644
                    } else {
645
                        // in any other case just change the status and ignore spinners/waves
646
                        existing.find(".status").text(STATUSES[server.status]);
647
                        existing.appendTo("#machinesview-icon.standard .running");
648
                        existing.find('.state').removeClass().addClass('state running-state');
649
                    }
650
                }
651
            }
652
            // find and display ips
653
            var ips = get_public_ips(server);
654
            existing.find("span.ip span.public").text(ips['ip4']);
655
            existing.find("span.ip span.public.ipv6-text").text(ips['ip6']);
656
        }
657
        // if it doesn't exist and the server is not DELETED, make a new entry
658
        else if ( server.status != 'DELETED') {
659
            // clone the proper template and put basic values in
660
            var machine = $("#machinesview-icon.standard #machine-container-template").clone().attr("id", server.id).fadeIn("slow");
661

662
            machine.find(".scrollable").scrollable({vertical: true});
663
            machine.find("div.name span.name").text(fix_server_name(server.name));
664
            machine.find("span.imagetag").text(server_image);
665
            machine.find(".status").text(STATUSES[server.status]);
666
            // check server status to select where to append the new server to
667
            if (ACTIVE_STATES.indexOf(STATUSES[server.status]) >= 0 ) {
668
                // append to running
669
                set_machine_os_image(machine, "icon", "on", server_image);
670
                machine.appendTo("#machinesview-icon.standard .running");
671
            } else {
672
                // append to terminated
673
                set_machine_os_image(machine, "icon", "off", server_image);
674
                machine.appendTo("#machinesview-icon.standard .terminated");
675
                if (server.status == "STOPPED") { //if server status us stopped is a different case than status unknown/error
676
                    machine.find('.state').removeClass().addClass('state terminated-state');
677
                } else {
678
                       machine.find('.state').removeClass().addClass('state error-state');
679
                }
680
            }
681

682
            //show spinner if server is still building or rebooting
683
            if (server.status == 'BUILD') {
684
                machine.find('.spinner').show();
685
                machine.find('.state').removeClass().addClass('state build-state');
686
                machine.addClass('vm-building');
687
            } else {
688
                machine.removeClass('vm-building');
689
            }
690

691
            if (server.status == 'REBOOT') {
692
                machine.find('.spinner').show();
693
                machine.find('.state').removeClass().addClass('state rebooting-state');
694
            }
695
            // find and display flavor parameters
696
            var flavor_params = get_flavor_params(server.flavorRef);
697
            machine.find(".cpu-data").text(flavor_params['cpus']);
698
            machine.find(".ram-data").text(flavor_params['ram']);
699
            machine.find(".disk-data").text(flavor_params['disk']);
700
            // find and display image parameters
701
            var image_params = get_image_params(server.imageRef);
702
            machine.find(".image-data").text(image_params['name'].substring(0,15));
703
            machine.find(".image-size-data").text(image_params['size']);
704
            // find and display ips
705
            var ips = get_public_ips(server);
706
            machine.find("span.ip span.public").text(ips['ip4']);
707
            machine.find("span.ip span.public.ipv6-text").text(ips['ip6']);
708

709
            // add stats images error events handlers
710
            $("img.cpu, img.net").error(function(){
711
                $(this).hide();
712
                $(this).parent().find(".stat-error").show();
713
            }).load(function(){
714
                $(this).show();
715
                $(this).parent().find(".stat-error").hide();
716
            });
717
        }
718
        /*
719
        Do some repeated actions that include:
720
            1. Update actions
721
            2. Metadata list updating
722
        */
723
        update_iconview_actions(server.id, server.status);
724
        if (!(server.metadata == undefined)) {
725
                list_metadata_keys(server.id, server.metadata.values);
726
        }
727

728
        // if machine in destroy state keep it that way
729
        var server = get_machine(server.id);
730
        if (server.status == "DESTROY") {
731
            existing = $('#machinesview-icon.standard #' + server.id);
732
            if (existing.length) {
733
                $(existing).find('.status').text(TRANSITIONS['Destroying']);
734
                $(existing).find('.state').removeClass().addClass('state destroying-state');
735
                $(existing).find('.spinner').show();
736
                $(existing).find('.wave').hide();
737
            }
738
        }
739
    });
740
    /*
741
    Do some standard stuff, repeated each time
742
    FIXME: Can these be moved to a new function?
743
    */
744
    fix_v6_addresses();
745
    $("div.large-spinner").hide();
746
    $("div.running").removeClass("disabled");
747
    // show all separators and hide the last one
748
    $("#machinesview-icon.standard div.machine-container div.separator").show();
749
    $("#machinesview-icon.standard div.machine-container:last-child").find("div.separator").hide();
750
    // the terminated div shows only when terminated machines are available
751
    if ($("#machinesview-icon.standard .terminated div.name").length > 0) {
752
        $("div.terminated").fadeIn("slow");
753
    } else {
754
        $("div.terminated").fadeOut("slow");
755
    }
756
    // show message in case user has no servers!
757
    if ($('#machinesview-icon .machine-container').length < 2) {
758
        showWelcome();
759
    } else {
760
        hideWelcome();
761
    }
762
    // set confirm box position
763
    if (window.innerHeight - CONFIRMBOX_OFFSET < $('#machinesview-icon.standard').height()) {
764
        $('.confirm_multiple').addClass('fixed');
765
    } else {
766
        $('.confirm_multiple').removeClass('fixed');
767
    }
768

769
    update_transition_names();
770
}
771

772
// reposition multiple confirmation box on window resize
773
$(window).resize(function(){
774
    if (this.innerHeight - CONFIRMBOX_OFFSET < $('#machinesview-icon').height())
775
        $('.confirm_multiple').addClass('fixed');
776
    else
777
        $('.confirm_multiple').removeClass('fixed');
778
});
779

780
// update metadata list
781
function list_metadata_keys(serverID, keys) {
782
    // empty the list if it already exists
783
    $("#machinesview-icon.standard div.#" +serverID).find("div.items").empty();
784
    //start counter
785
    var i=0;
786
    // show values
787
    for (var key in keys) {
788
        $("#machinesview-icon.standard div.#" +serverID).find(".items").append("<div class='item'>" + key + "</div>");
789
        i++;
790
    }
791
    //hide the metadata controls if we have less than 3 metadata
792
    if (i <= 3) {
793
        $("#machinesview-icon.standard div.#" +serverID).find(".metadata-actions").hide();
794
    }
795
    //show the metadata controls if we have more than 3 metadata
796
    if (i > 3) {
797
        $("#machinesview-icon.standard div.#" +serverID).find(".metadata-actions").show();
798
    }
799
    $("#machinesview-icon.standard div.#" +serverID).find(".metadata-count").text(i);
800
}
801

802
// define these to avoid exceptions
803
function display_reboot_success() {
804
}
805

806
function display_reboot_failure() {
807
}
808

809
// append string to transition states
810
function update_transition_names() {
811
    $(".state .status").each(function(index,el){
812
    var tr_text = $(this).text().replace(TRANSITION_STATE_APPEND,"");
813
    if (TRANSITION_STATES.indexOf(tr_text) >= 0) {
814
            $(this).text(tr_text + TRANSITION_STATE_APPEND);
815
        }
816
    })
817
}
818

819
// indicate that the requested action was succesfully completed
820
function display_success(serverID) {
821

822
}
823

824
// indicate that the requested action was not completed
825
function display_failure(status, serverID, action, responseText) {
826
    $('#machinesview-icon.standard #'+serverID+ ' .spinner').hide();
827
    $('#machinesview-icon.standard #'+serverID+ ' .action_error .action').text(action);
828
    $('#machinesview-icon.standard #'+serverID+ ' .action_error .code').text(status);
829
    $('#machinesview-icon.standard #'+serverID+ ' .action_error .message').text(responseText);
830
    $('#machinesview-icon.standard #'+serverID+ ' .action_error').show();
831
}
832

833
// handle update stats
834
function update_server_stats() {
835
    // TODO: only reload images for expanded machines
836
    $(".vm-stats").each(function(){
837
        var serverID = $(this).closest(".machine-container").attr("id");
838
        get_server_stats(serverID);
839
    });
840
}
841

842
// basic functions executed on page load
843
if ( flavors.length == 0 && images.length == 0 ) {
844
    // configure flavors, this also calls update_vms(UPDATE_INTERVAL)
845
    update_flavors();
846
    // populate image list
847
    update_images();
848
} else if ( flavors.length == 0 && images.length != 0 ) {
849
    // configure flavors, this also calls update_vms(UPDATE_INTERVAL)
850
    update_flavors();
851
} else if ( flavors.length != 0 && images.length == 0 ) {
852
    // populate image list
853
    update_images();
854
    update_vms(UPDATE_INTERVAL);
855
} else {
856
    // start updating vm list
857
    update_vms(UPDATE_INTERVAL);
858
}
859

860
// set the label of the multiple buttons
861
$('.confirm_multiple button.yes').text('Confirm All');
862
$('.confirm_multiple button.no').text('Cancel All');
863

864
//IE specific fixes
865
if ($.browser.msie) {
866
    //IE fix for machine div hover
867
    $("div.machine").live("mouseenter", function () {
868
        $(this).css("background-color","#A1C8DB");
869
        $(this).find("div.info-header").css("background-color","#84b7d0");
870
        $(this).find("div.toggler div.down").css("background-color","#84b7d0");
871
        $(this).find(".actions a").css("visibility","visible");
872
    });
873
    $("div.machine").live("mouseleave", function () {
874
        $(this).css("background-color","transparent");
875
        $(this).find("div.info-header").css("background-color","#A1C8DB");
876
        $(this).find("div.toggler div.down").css("background-color","#A1C8DB");
877
        if ($(this).parent().find(".confirm_single:visible").length == 0) {
878
            $(this).find(".actions a").css("visibility","hidden");
879
        }
880
    });
881
    //IE fix for green arrow hover
882
    $("div.connect-arrow").live("mouseenter", function () {
883
        $(this).addClass("connect-arrow-ie");
884
    });
885
    $("div.connect-arrow").live("mouseleave", function () {
886
        $(this).removeClass("connect-arrow-ie");
887
    });
888
    //IE fix for details button
889
    $("button.details").live("mouseenter", function () {
890
        $(this).css("background-color","#FF7F2A");
891
    });
892
    $("button.details").live("mouseleave", function () {
893
        $(this).css("background-color","transparent");
894
    });
895
    //IE fix for multiple conf yes button
896
    $("div.confirm_multiple button.yes").live("mouseenter", function () {
897
        $(this).css("background-color","#FF7F2A");
898
    });
899
    $("div.confirm_multiple button.yes").live("mouseleave", function () {
900
        $(this).css("background-color","transparent");
901
    });
902
    //IE fix for multiple conf no button
903
    $("div.confirm_multiple button.no").live("mouseenter", function () {
904
        $(this).css("background-color","#5CA1C0");
905
    });
906
    $("div.confirm_multiple button.no").live("mouseleave", function () {
907
        $(this).css("background-color","transparent");
908
    });
909

910

911
}
912

913
$(".stats-report").live('click', function(){
914
    var el = $(this);
915
    var srvID = el.closest(".machine-container").attr("id");
916

917
    $.cookie('server', srvID);
918
    $('a#single').click();
919
})
920
</script>