Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ abf90954

History | View | Annotate | Download (20.9 kB)

1
{% load i18n %}
2

    
3
<div id="machines" class="seperator"></div>
4

    
5
<!-- the create button -->
6
<a id="create" rel="#wizard" href="#">{% trans "Create New +" %}</a>
7

    
8
<!-- changing between standard/list view -->
9
<div id="view-select">
10
    <a id="standard" class="current" href="/machines">#</a>
11
    <span class="view-seperator">|</span>
12
    <a id="list" href="/machines/list">=</a>
13
</div>
14

    
15
<!-- the standard view -->
16
<div id="machinesview" class="standard">
17
    <div id="spinner"></div>
18
    <div class="machine" id="machine-template" style="display:none">
19
        <div class="state">
20
            <div class="status">{% trans "Running" %}</div>
21
            <div class="indicator"></div>
22
            <div class="indicator"></div>
23
            <div class="indicator"></div>
24
            <div class="indicator"></div>
25
        </div>
26
        <img class="logo" src="" />
27
        <a href="#" class="name">
28
            <h5>Νame: <span class="name">node.name</span><span class="rename"></span></h5>
29
        </a>
30
        <a href="#" class="ip">
31
            <h5>IP: <span class="public">node.public_ip</span></h5>
32
        </a>
33
        <h5 class="settings">
34
            {% trans "Show:" %} <a href="#">{% trans "disks" %}</a> | <a href="#">{% trans "networks" %}</a> | <a href="#">{% trans "group" %}</a>
35
        </h5>
36
        <div class="actions">
37
            <a href="#" class="action-reboot">{% trans "Reboot" %}</a>
38
            <a href="#" class="action-shutdown">{% trans "Shutdown" %}</a>
39
            <a href="#" class="more">{% trans "more &hellip;" %}</a>
40
        </div>
41
        <div class="seperator"></div>
42
    </div>
43

    
44
    <div class="running"></div>
45
    <div id="mini" class="seperator"></div>
46
    <div class="terminated"></div>
47
</div>
48

    
49
<div id="machines" class="seperator"></div>
50

    
51
<!-- the form -->
52
<form action="#">
53
        <!-- scrollable root element -->
54
        <div class="modal" id="wizard">
55
                <!-- status bar -->
56
                <ul id="status">
57
                        <li class="active"><strong>1.</strong> {% trans "Image" %}</li>
58
                        <li><strong>2.</strong> {% trans "Machine" %}</li>
59
                        <li><strong>3.</strong> {% trans "Review" %}</li>
60
                </ul>
61
                <!-- scrollable items -->
62
                <div class="items">
63
                        <!-- pages -->
64
                        <div class="page">
65
                <h2>{% trans "Select an OS" %}</h2>
66
                <ul class="tabs">
67
                    <li><a href="#">{% trans "standard" %}</a></li>
68
                    <li><a href="#">{% trans "custom" %}</a></li>
69
                </ul>
70
                <div class="panes">
71
                            <li id="image-template" style="display:none">
72
                                    <label for="image.id"> 
73
                            <a><div class="image">
74
                                <img src="" class="image-logo"/>
75
                                <strong class="image-title">image.title</strong>
76
                                <input class="radio" type="radio" name="image-id" id="image-id" />
77
                                <br />
78
                                <span class="description">image.description</span> 
79
                                <span class="size">?? MB</span>
80
                                
81
                            </div></a>
82
                                    </label>
83
                            </li>
84
                    <ul class="pane" id="standard-images">
85
                                            <!-- standard images -->
86
                                    </ul>
87
                    <ul class="pane" id="custom-images">
88
                                            <!-- custom images -->
89

    
90
                    </ul>
91
                </div>
92
                                <button type="button" class="prev" id="cancel">{% trans "Cancel" %}</button>
93
                                <button type="button" class="next right">{% trans "Next" %} &raquo;</button>
94
            </div>
95
                        <div class="page">
96
                                <h2>{% trans "Select CPU, RAM and storage" %}</h2>
97
                <ul>
98
                    <li>
99
                        <div class="machine-type">
100
                            <label for="small">
101
                                <input type="radio" id="small" name="machine-type" value="small" checked="true" />
102
                                <strong>{% trans "small" %}</strong>
103
                            </label>
104
                        </div>
105
                        <div class="machine-type">      
106
                            <label for="medium">
107
                                <input type="radio" id="medium" name="machine-type" value="medium" />                  
108
                                <strong>{% trans "medium" %}</strong>
109
                            </label>
110
                        </div>
111
                        <div class="machine-type">
112
                            <label for="large">
113
                                <input type="radio" id="large" name="machine-type" value="large" />
114
                                <strong>{% trans "large" %}</strong>
115
                            </label>
116
                        </div>
117
                        <div class="machine-type">
118
                            <label for="custom">
119
                                <input type="radio" name="machine-type" id="custom" value="large" />
120
                                <strong>{% trans "custom" %}</strong>
121
                            </label>
122
                        </div>
123
                    </li>
124
                    <li>
125
                                    <label><strong class="sliders">CPU (cores)</strong></label>
126
                        <input type="range" id="cpu" value="1" max="8" min="1" />
127
                    </li>
128
                    <li>
129
                                    <label><strong class="sliders">RAM (MB)</strong></label>
130
                        <input type="range" id="ram" value="256" max="2048" min="256" step="256" />
131
                    </li>
132
                    <li>
133
                                <label><strong class="sliders">Storage (GB)</strong></label>
134
                        <input type="range" id="storage" value="5" step="1" max="100" min="2" />
135
                    </li>
136
                    <li>
137
                        <div class="cost">
138
                            {% trans "Cost per hour:" %} 20 {% trans "credits" %} | {% trans "Credits currently in account:" %} 10.000
139
                        </div>
140
                    </li>
141
                </ul>
142
                                <button type="button" class="prev">&laquo; {% trans "Back" %}</button>
143
                                <button type="button" class="next right">{% trans "Next" %} &raquo;</button>
144
            </div>
145
                        <div class="page">
146
                                <h2>{% trans "Confirm your settings" %}</h2>
147
                <ul>
148
                    <li class="required">
149
                        <label>
150
                            <strong>Machine name</strong>
151
                            <input type="text" class="text" name="machine_name" value="My Ubuntu 10.04 x86_64 server"/>
152
                        </label>
153
                    </li>
154
                    <li>
155
                        <strong>{% trans "Image:" %}</strong> <span>Ubuntu 10.04 x86_64 server</span>
156
                    </li>
157
                    <li>
158
                        <strong>{% trans "CPU:" %}</strong> <span>2 cores</span>
159
                    </li>
160
                    <li>
161
                        <strong>{% trans "RAM:" %}</strong> <span>1024MB</span>
162
                    </li>
163
                    <li>
164
                        <strong>{% trans "Storage:" %}</strong> <span>10GB</span>
165
                    </li>
166
                    <li>
167
                        <strong>{% trans "Cost per hour:" %}</strong> <span>20 {% trans "credits" %}</span>
168
                    </li>
169
                    <li>
170
                        <strong>{% trans "Remaining credits:" %}</strong> <span>10.000</span>
171
                    </li>
172
                </ul>
173
                                <button type="button" class="prev">&laquo; {% trans "Back" %}</button>
174
                                <button type="button" class="next right" id="start">{% trans "Create VM" %}</button>        
175
            </div>
176
                </div>
177
        </div>
178
</form>
179

    
180
<!-- notification after wizard completion -->
181
<a id="notify" rel="#creation-note" href="#"></a>
182

    
183
<div class="modal" id="creation-note">
184
    <h3>Your VM is being created!</h3>
185
    <p>{% trans "Your password is:" %}<strong> sdeEFre</strong></p>
186
    <p>{% trans "Please copy this! Without it you can not connect to your VM." %}</p>
187
</div>
188

    
189
<!-- verification before executing an action -->
190
<a id="verification" rel="#yesno" href="#"></a>
191

    
192
<div class="modal" id="yesno">
193
    <h3>You are about to</h3>
194
    <p>This action reffers to the following machines:</p>
195
    <ul>
196
        <li>machine1</li>
197
        <li>...</li>
198
    </ul>
199
    <p>Are you sure you want to proceed?</p>
200
    <button> Yes </button>
201
        <button> No </button>
202
</div>
203

    
204
<script>
205

206
// hardcoded image types
207
var image_tags = {
208
                1: 'archlinux',
209
                2: 'centos',
210
                3: 'debian',
211
                4: 'freebsd',
212
                5: 'gentoo',
213
                6: 'netbsd',
214
                7: 'openbsd',
215
                8: 'redhat',
216
                9: 'slackware',
217
                10: 'suse',
218
                11: 'ubuntu',
219
                12: 'windows',
220
                20: 'ubuntu',
221
               };
222

223
// create tabs for main menu
224
$("ul.tabs").tabs("div.panes ul");
225

226
// get and show list of running and terminated machines
227
function update() {
228

229
    $(".running").text('');
230
    $(".terminated").text('');
231
    $("ul#standard-images").text('');
232
    $("ul#custom-images").text('');
233
    $.ajax({
234
        url: '/api/v1.0/servers/detail',
235
        type: "GET",
236
        //async: false,
237
        dataType: "json",
238
        timeout: {{timeout}},
239
        error: function(data, strError) {
240
                    $("#spinner").hide();
241
                    if (strError == 'timeout'){
242
                        alert('{% trans "timeout error. Check your network connection" %}');
243
                        return false;
244
                                              }
245
                    else{
246
                        alert('{% trans "Cannot connect to the backend! Please inform the admins" %}');
247
                        return false;
248
                        }
249
                          },
250
        success: function(data) {
251
            if ($(".running a.name").length + $(".terminated a.name").length == 0) {
252
            
253
                $.each(data.servers, function(i,server){
254
                    // if the machine is deleted it should not be included in any list
255
                    if (server.status == 'DELETED') {
256
                        return;
257
                    }
258
                    var machine = $("#machine-template").clone().attr("id", server.id).fadeIn("slow");
259
                    machine.find("input[type='checkbox']").attr("id", "input-" + server.id);
260
                    machine.find("input[type='checkbox']").attr("class", server.status);
261
                    machine.find("a.name span.name").text(server.name);
262
                    machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'.png');
263
                    machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'.png');
264
                    machine.find("img.list-logo").attr("title",image_tags[server.imageId]);
265
                    machine.find("span.imagetag").text(image_tags[server.imageId]);
266
    
267
                    machine.find("a.ip span.public").text(String(server.metadata.addresses.public).replace(',',' '));            
268
    
269
                    // TODO: handle SHARE_IP, SHARE_IP_NO_CONFIG, DELETE_IP, REBUILD, QUEUE_RESIZE, PREP_RESIZE, RESIZE, VERIFY_RESIZE, PASSWORD, RESCUE
270
                    if (server.status == 'BUILD'){
271
                        machine.find(".status").text('Building');
272
                        machine.appendTo(".running");
273
                    } else if (server.status == 'ACTIVE') {
274
                        machine.find(".status").text('Running');
275
                        machine.appendTo(".running"); 
276
                    } else if (server.status == 'REBOOT' || server.status == 'HARD_REBOOT') {
277
                        machine.find(".status").text('Rebooting');
278
                        machine.appendTo(".running");
279
                    } else if (server.status == 'STOPPED') {
280
                        machine.find(".status").text('Stopped');
281
                        machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
282
                        machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
283
                        machine.appendTo(".terminated");
284
                    } else if (server.status == 'ERROR') {
285
                        machine.find(".status").text('Error');
286
                        machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
287
                        machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
288
                        machine.appendTo(".terminated");
289
                    } 
290
                    else {
291
                        machine.find(".status").text('Unknown');
292
                        machine.find("img.logo").attr("src","static/machines/"+image_tags[server.imageId]+'-off.png');
293
                        machine.find("img.list-logo").attr("src","static/os_logos/"+image_tags[server.imageId]+'-off.png');
294
                        machine.appendTo(".terminated");
295
                    }
296
                });
297
                // if the terminated list is populated then the seperator must be shown
298
                if ($(".terminated a.name").length > 0) {
299
                    $("#mini.seperator").fadeIn("slow");
300
                }
301
            }
302
            $("div.machine:last-child").find("div.seperator").hide();
303
            $("#spinner").hide();
304
            if ($("div.list table.list-running tbody.running tr").length > 0) {
305
                $(".list table.list-running").tablesorter({ 
306
                    headers: { 0: { sorter: false}, 6: { sorter: false }}, 
307
                    sortMultiSortKey: "ctrlKey" }).show();
308
                $(".list .actions").show();
309
            }
310
            if ($("div.list table.list-terminated tbody.terminated tr").length > 0) {
311
                $(".list table.list-terminated").tablesorter({ 
312
                    headers: { 0: { sorter: false}, 6: { sorter: false }}, 
313
                    sortMultiSortKey: "ctrlKey" }).show();
314
                $(".list .actions").show();
315
            }
316
        }
317
    });
318

319
    $.ajax({
320
        url: '/api/v1.0/images/detail',
321
        type: "GET",
322
        //async: false,
323
        dataType: "json",
324
        timeout: {{timeout}},
325
        error: function(data, strError) {
326
                    if (strError == 'timeout'){
327
                        alert('{% trans "timeout error. Check your network connection" %}');
328
                        return false;
329
                                              }                    
330
                          },
331
        success: function(data) {
332
            if ($("ul#standard-images li").toArray().length + $("ul#custom-images li").toArray().length == 0) {
333
                $.each(data.images, function(i,image){
334
                    var img = $('#image-template').clone().attr("id","img-"+image.id).fadeIn("slow");
335
                    img.find("label").attr('for',"img-radio-" + image.id);
336
                    img.find(".image-title").text(image.name);
337
                    img.find(".description").text(image.description);
338
                    img.find("input.radio").attr('id',"img-radio-" + image.id);
339
                    if (i==0) img.find("input.radio").attr("checked","checked"); 
340
                    img.find("img.image-logo").attr('src','static/os_logos/'+image_tags[image.id]+'.png');
341
                    if (image.serverId) {
342
                        img.appendTo("ul#custom-images");
343
                    } else {
344
                        img.appendTo("ul#standard-images");
345
                    }
346
                });
347
            }
348
        }
349
    });
350
    return false;
351
}
352

353
// switch to list view
354
$("#list").click(function(){
355
    $.cookie("list", '1'); // set list cookie
356
    $("div.standard#machinesview").load($("#list").attr("href"));
357
    $("a#standard")[0].className += ' activelink'
358
    this.style.color = '#5f8dd3';
359
    update();
360
    return false;
361
});
362

363
// switch to standard view
364
$("a#standard").click(function(){
365
    $.cookie("list", '0');
366
    href=$("a#standard").attr("href");
367
    $("div.pane#machines-pane").load(href);
368
    //$("a#standard")[0].className += ' activelink'
369
    //this.style.color = '#5f8dd3';
370
    return false;
371
});
372

373
// redirect to list view if the list cookie is set
374
if ($.cookie("list") == '1') {
375
    $("#list").click();
376
} else {
377
    // execute the update function to populate the list
378
    update();
379
}
380

381
// launch VM creation wizard
382
$("a#create").click(function(){
383
    $("#wizard").scrollable().begin();
384
});
385

386
// create wizard overlay
387
$(function() { 
388
    $("a#create[rel]").overlay({
389
        mask: '#000', 
390
        effect: 'default', 
391
        top: '5%', 
392
        oneInstance: false,
393
        closeOnClick: false
394
    });
395
});
396

397
// wizard
398
$(function() {
399
    var root = $("#wizard").scrollable();
400

401
    // some variables that we need
402
    var api = root.scrollable();
403

404
    // rangeinput with default configuration
405
    // validation logic is done inside the onBeforeSeek callback
406
    api.onBeforeSeek(function(event, i) {
407
            // we are going 1 step backwards so no need for validation
408
            if (api.getIndex() < i) {
409
             // 1. get current page
410
                     var page = root.find(".page").eq(api.getIndex()),
411
                         // 2. .. and all required fields inside the page
412
                         inputs = page.find(".required :input").removeClass("error"),
413
                         // 3. .. which are empty
414
                         empty = inputs.filter(function() {
415
                                return $(this).val().replace(/\s*/g, '') == '';
416
                         });
417
                     // if there are empty fields, then
418
                    if (empty.length) {
419
                            // add a CSS class name "error" for empty & required fields
420
                            empty.addClass("error");
421
                            // cancel seeking of the scrollable by returning false
422
                            return false;
423
                    // everything is good
424
                    } 
425
            }
426
            // update status bar
427
            $("#status li").removeClass("active").eq(i).addClass("active");
428
    });
429

430
    // if tab is pressed on the next button seek to next page
431
    root.find("button.next").keydown(function(e) {
432
            if (e.keyCode == 9) {
433
                    // seeks to next tab by executing our validation routine
434
                    api.next();
435
                    e.preventDefault();
436
            }
437
    });
438
});
439

440
// sliders for selecting VM flavor
441
$(":range").rangeinput({progress:true});
442

443
// disable sliders in flavor selection
444
function disableSliders() {
445
    $("#cpu").attr('disabled',true);
446
    $("#ram").attr('disabled',true);
447
    $("#storage").attr('disabled',true);
448
}
449

450
// selecting the small size
451
$("#small").click(function(){
452
    $("#cpu").data('rangeinput').setValue(1);
453
    $("#ram").data('rangeinput').setValue(256);
454
    $("#storage").data('rangeinput').setValue(5);
455
});
456

457
// selecting the medium size
458
$("#medium").click(function(){
459
    $("#cpu").data('rangeinput').setValue(4);
460
    $("#ram").data('rangeinput').setValue(1024);
461
    $("#storage").data('rangeinput').setValue(30);
462
});
463

464
// selecting the large size
465
$("#large").click(function(){
466
    $("#cpu").data('rangeinput').setValue(8);
467
    $("#ram").data('rangeinput').setValue(4096);
468
    $("#storage").data('rangeinput').setValue(80);
469
});
470

471
// selecting the custom flavor enables the sliders
472
$("#custom").click(function(){
473
    $("#cpu").attr('disabled',false);
474
    $("#ram").attr('disabled',false);
475
    $("#storage").attr('disabled',false);
476
    $("strong.sliders").style = 'color: #778899;';
477
});
478

479
// get cpu value for custom flavor
480
$("#cpu").change(function(){
481
    $("#custom").click();
482
});
483

484
// get ram value for custom flavor
485
$("#ram").change(function(){
486
    $("#custom").click();
487
});
488

489
// get storage value for custom flavor
490
$("#storage").change(function(){
491
    $("#custom").click();
492
});
493

494
// exit the wizard
495
$("#cancel").click(function(){
496
    $("a#create[rel]").overlay().close();
497
});
498

499
// starting a new VM through the wizard
500
$("#start").click(function(){
501
    // send create call
502
    $.ajax({
503
    url: '/api/v1.0/servers',
504
    type: "POST",
505
    data: {
506
        "create": {"foo" : "foo"}
507
        },
508
    //TODO: get the real data
509
    //async: false,
510
    dataType: "json",
511
    success: function() {}
512
    });
513
    // bring up notification
514
    var triggers = $("a#notify").overlay({
515
            // some mask tweaks suitable for modal dialogs
516
            mask: {
517
                    color: '#ebecff',
518
                    opacity: '0.9'
519
            },
520
        top: 'center',
521
            closeOnClick: false,
522
        oneInstance: false,
523
        load: true,
524
        onClose: function(){
525
            $("div.pane#machines-pane").load($("a#standard").attr("href"));
526
        }
527
    });
528
    $("#wizard").hide();
529
    update();
530
});
531

532
// reboot action
533
function reboot(){
534
    var serverID = $(this).parent().parent().attr("id");
535
    alert("rebooting " + serverID);
536
    $.ajax({
537
            url: '/api/v1.0/servers/' + serverID + '/action',
538
            type: "POST",
539
            data: {
540
                    "reboot": '{"type" : "HARD"}'
541
                    },
542
            //async: false,
543
            dataType: "json",
544
            success: function() {},
545
    });
546
    return false;
547
}
548

549
// shutdown action
550
function shutdown() {
551
    var serverID = $(this).parent().parent().attr("id");
552
    alert("shutting down " + serverID);
553
        $.ajax({
554
                url: '/api/v1.0/servers/' + serverID + '/action',
555
                type: "POST",
556
                data: {
557
                        "shutdown": '{"timeout" : "5"}'
558
                        },
559
                //async: false,
560
                dataType: "json",
561
                success: function() {}
562
        });
563
    return false;    
564
}
565

566
// intercept action clicks
567
$("div.actions a.action-shutdown").live('click', shutdown);
568
$("div.actions a.action-reboot").live('click', reboot);
569

    
570

    
571
</script>