Statistics
| Branch: | Tag: | Revision:

root / ui / templates / machines.html @ 67679131

History | View | Annotate | Download (21.6 kB)

1
{% load i18n %}
2

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

    
5
<!-- the create button -->
6
<div id="createcontainer">
7
    <span id="createbody">{% trans "Start by creating a new Virtual Machine:" %}</span><br />
8
    <a id="create" rel="#wizard" href="#">{% trans "Create New +" %}</a>
9
</div>
10

    
11
<!-- changing between standard/list view -->
12
<div id="view-select">
13
    <a id="standard" href="/machines/standard"></a>
14
    <a id="list" href="/machines/list"></a>
15
    <a id="single" href="#"></a>
16
</div>
17

    
18
<div id="emptymachineslist"><h1 id="welcomeheader">{% trans "Welcome to the ocean!" %}</h1><br />
19
    <span class="welcomebody">{% trans "From this panel you will be able to manage your Virtual Machines (VMs). If you don't know what a VM is: take the " %}<a href="#">{% trans "tour" %}</a>.</span><br /><br />
20
    <span class="welcomebody">{% trans "The panel is currently empty, because you don't have any VMs yet. You can start by creating your new VM by clicking the blue button on the right. The wizard will guide you through the hole process." %}</span><br /><br />
21
    <span class="welcomefooter">{% trans "For more information or help, click " %}<a href="#">{% trans "here" %}</a>.</span>
22
</div>
23

    
24
<!-- the form -->
25
<form action="#">
26
        <!-- scrollable root element -->
27
        <div class="modal" id="wizard">
28
                <!-- status bar -->
29
                <ul id="status">
30
                        <li class="active"><span class="headernumber" class="first">1</span><div class="headerbody first">{% trans "Image" %}</div></li>
31
                        <li><span class="headernumber">2</span><div class="headerbody">{% trans "Flavor" %}</div></li>
32
                        <li class="third"><span class="headernumber">3</span><div class="headerbody">{% trans "Name" %}</div></li>
33
                </ul>
34
                <!-- scrollable items -->
35
                <div class="items">
36
                        <!-- pages -->
37
                        <div class="page">
38
                <h2>{% trans "Select an OS" %}</h2>
39
                <hr class="topruler" />
40
                <ul class="tabs">
41
                    <li><a href="#">{% trans "system images" %}</a></li>
42
                    <li><a href="#">{% trans "custom images" %}</a></li>
43
                </ul>
44
                <div class="panes">
45
                            <li id="image-template" style="display:none">
46
                                    <label for="image.id"> 
47
                            <a>
48
                                <div class="image-container">
49
                                    <div class="image">
50
                                        <input class="radio" type="radio" name="image-id" id="image-id" />
51
                                        <img src="" class="image-logo"/>
52
                                        <strong class="image-title">image.title</strong>
53
                                        <br />
54
                                        <span class="description">image.description</span> 
55
                                        <span id="size" class="size">?? MB</span><span class="size"> MB</span>                         
56
                                    </div>
57
                                </div>  
58
                            </a>
59
                                    </label>
60
                            </li>
61
                    <ul class="pane" id="standard-images">
62
                                            <!-- standard images -->
63
                                    </ul>
64
                    <ul class="pane" id="custom-images">
65
                                            <!-- custom images -->
66
                    </ul>
67
                </div>
68
                <hr class="bottomruler" />
69
                                <button type="button" class="prev" id="cancel">{% trans "Cancel" %}</button>
70
                                <button type="button" class="next right">{% trans "Next" %}</button>
71
            </div>
72
                        <div class="page">
73
                                <h2>{% trans "Select CPUs, RAM and Disk Size" %}</h2>
74
                <hr class="topruler" />
75
                <ul>
76
                    <li id="machinetype">
77
                        <div class="machine-type">
78
                            <label for="small" id="small">
79
                                <input type="radio" id="small" name="machine-type" value="small" checked="true" />
80
                                <span class="typebody" id="small-body">{% trans "small" %}</span>
81
                            </label>
82
                        </div>
83
                        <div class="machine-type">      
84
                            <label for="medium" id="medium">
85
                                <input type="radio" id="medium" name="machine-type" value="medium" />                  
86
                                <span class="typebody" id="medium-body">{% trans "medium" %}</span>
87
                            </label>
88
                        </div>
89
                        <div class="machine-type">
90
                            <label for="large" id="large">
91
                                <input type="radio" id="large" name="machine-type" value="large" />
92
                                <span class="typebody" id="large-body">{% trans "large" %}</span>
93
                            </label>
94
                        </div>
95
                        <div class="machine-type">
96
                            <label for="custom" id="custom">
97
                                <input type="radio" name="machine-type" id="custom" value="large" />
98
                                <span class="typebody" id="custom-body">{% trans "custom" %}</span>
99
                            </label>
100
                        </div>
101
                    </li>
102
                    <div id="page2-container">
103
                        <li class="slider-container">
104
                                        <label><strong class="sliders">CPUs</strong></label>
105
                            <input type="range" id="cpu" style="display:none" />
106
                            <input type="text" class="range" id="cpu-indicator" />
107
                                        <span class="units">cores</span>
108
                        </li>
109
                        <li class="slider-container">
110
                                        <label><strong class="sliders">RAM</strong></label>
111
                            <input type="range" id="ram" style="display:none" />
112
                            <input type="text" class="range" id="ram-indicator" />
113
                                        <span class="units">MB</span>
114
                        </li>
115
                        <li class="slider-container">
116
                                    <label><strong class="sliders">Size</strong></label>
117
                            <input type="range" id="storage" style="display:none" />
118
                            <input type="text" class="range" id="storage-indicator" />
119
                                        <span class="units">GB</span>
120
                        </li>
121
                        <li>
122
                            <div class="cost">
123
                                <span> {% trans "Your wallet:" %} 10,000 Credits </span> | <span>{% trans "This setup will cost you:" %}<input type="text" id="credits-indicator" value="20" class="range" /> {% trans "C/hour" %}</span>
124
                            </div>
125
                        </li>
126
                    </div>
127
                </ul>
128
                <hr class="bottomruler" />
129
                                <button type="button" class="prev">{% trans "Back" %}</button>
130
                                <button type="button" class="next right">{% trans "Next" %}</button>
131
            </div>
132
                        <div class="page">
133
                                <h2>{% trans "Confirm your settings" %}</h2>
134
                <hr class="topruler" />
135
                <ul id="page3-container">
136
                    <li class="required" id="label-name">
137
                        <label>
138
                            <strong>Name:</strong>
139
                            <input type="text" class="text" name="machine_name" id="name" value="My Ubuntu 10.04 x86_64 server"/>
140
                        </label>
141
                    </li>
142
                    <li>
143
                        <span>{% trans "Image:" %}</span> <span id="machine_image-label">Ubuntu 10.04 x86_64 server</span>
144
                    </li>
145
                    <li>
146
                        <span>{% trans "CPUs:" %}</span> <span id="machine_cpu-label">2</span> <span>{% trans "cores" %}</span>
147
                    </li>
148
                    <li>
149
                        <span>{% trans "RAM:" %}</span> <span id="machine_ram-label">1024</span><span>MB</span>
150
                    </li>
151
                    <li>
152
                        <span>{% trans "System Disk:" %}</span> <span id="machine_storage-label">10</span><span>GB</span>
153
                    </li>
154
                    <li>
155
                        <span>{% trans "Cost per Hour:" %}</span> <span>40 {% trans "credits" %}</span>
156
                    </li>
157
                    <li>
158
                        <span>{% trans "Credits in Wallet:" %}</span> <span>10.000</span>
159
                    </li>
160
                </ul>
161
                <hr class="bottomruler" />
162
                                <button type="button" class="prev">{% trans "Back" %}</button>
163
                                <button type="button" class="next right" id="start">{% trans "Create VM" %}</button>        
164
            </div>
165
                </div>
166
        </div>
167
</form>
168

    
169
<!-- base notification for error/success reporting -->
170
<a id="notification" rel="#error-success" href="#"></a>
171

    
172
<div class="modal" id="error-success">
173
    <h3>{% trans "Error!/Success!" %}</h3>
174
    <div><p>{% trans "More details about the result"%}</p></div>
175
</div>
176

    
177

    
178
<a id="meta-editor-1" rel="#editor-1" href="#"></a>
179

    
180
<div class="meta-modal" id="editor-1">
181
    <h3>
182
        <label>{% trans "Metadata for machine:" %}<label>
183
        <span></span>
184
    </h3>
185
    <hr class="topruler" />
186
    <hr class="fatruler" />
187
    <div class="content">
188
        <ul>
189
            <li class="meta-template">
190
                <label>{% trans "Metadata key" %}</label>
191
                <button type="button" class="remove">{% trans "remove x" %}</button>
192
                <hr class="meta-separator">
193
                <p>{% trans "Metadata value" %}</p>
194
                <button type="button" class="edit">{% trans "edit" %}</button>
195
            </li>
196
        </ul>
197
    </div>
198
    <button type="button" class="create">{% trans "Create New+" %}</button>
199
    <div class="bottomruler" /> 
200
</div>
201

    
202
<a id="meta-editor-2" rel="#editor-2" href="#"></a>
203

    
204
<div class="meta-modal" id="editor-2">
205
    <h3>
206
        <label>{% trans "Metadata for machine:" %}<label>
207
        <span></span>
208
    </h3>
209
    <hr class="topruler" />
210
    <hr class="fatruler" />
211
    <div class="content">
212
        <label class="meta-key">{% trans "Key:" %}</label>
213
        <input type="text" maxlength="15" class="key" value="max 15 characters"/>
214
        <hr class="meta-separator">
215
        <label class="meta-value">{% trans "Value:" %}</label>
216
        <input type="text" maxlength="150" class="value" value="max 150 characters"/>
217
    </div>
218
    <button type="button" class="cancel">{% trans "Cancel" %}</button>
219
    <button type="button" class="save">{% trans "Save" %}</button>
220
    <div class="bottomruler" /> 
221
</div>
222

    
223
<div id="machinesview"></div>
224

    
225
<div class="confirm_multiple">
226
    <p>{% trans "Your actions will affect" %} <span class="actionLen">XX</span> {% trans "machines" %}</p>
227
    <button class="yes">{% trans "Confirm All" %}</button>
228
        <button class="no">{% trans "Cancel All" %}</button>
229
</div>
230

    
231
<div id="machines" class="separator"></div>
232

    
233
<script>
234
//add hover to labels
235
$('span.typebody').mouseover(function() {
236
    $(this).addClass('typehover');
237
});
238
$('span.typebody').mouseout(function() {
239
    $(this).removeClass('typehover');
240
});
241

242
// return value from metadata key "OS", if it exists
243
function os_icon(metadata) {
244
    if (!metadata) {
245
        return 'unknown';
246
    }
247

248
    if (metadata.values.OS == undefined || metadata.values.OS == '') {
249
        return 'unknown';
250
    } else {
251
        return metadata.values.OS;
252
    }
253
} 
254

255
// switch to list view
256
$("a#list").click(function(){
257
    list_view(); 
258
    return false;
259
});
260

261
// switch to standard view
262
$("a#standard").click(function(){
263
    standard_view();
264
    return false;
265
});
266

267
// launch VM creation wizard
268
$("a#create").click(function(){
269
    // launch wizard only if images and flavors are found
270
    if (images.length > 0  && flavors.length > 0) {
271
        $("#wizard").scrollable().begin();
272
        $("#wizard").show();
273
        $('a#create').data('overlay').load()   
274
    } else if (images.length == 0 ) {
275
        ajax_error('NO_IMAGES');
276
        return false;   
277
    } else if (flavors.length == 0) {
278
        ajax_error('NO_FLAVORS');
279
        return false;
280
    }
281
});
282

283
// create wizard overlay
284
$(function() { 
285
    $("a#create").overlay({
286
        mask: '#000', 
287
        effect: 'default', 
288
        top: '5%', 
289
        oneInstance: false,
290
        closeOnClick: false
291
    });
292
});
293

294
// wizard
295
$(function() {
296
    var root = $("#wizard").scrollable();
297
    var api = root.scrollable();
298
    // rangeinput with default configuration
299
    // validation logic is done inside the onBeforeSeek callback
300
    api.onBeforeSeek(function(event, i) {
301
            // we are going 1 step backwards so no need for validation
302
            if (api.getIndex() < i) {
303
             // 1. get current page
304
                     var page = root.find(".page").eq(api.getIndex()),
305
                         // 2. .. and all required fields inside the page
306
                         inputs = page.find(".required :input").removeClass("error"),
307
                         // 3. .. which are empty
308
                         empty = inputs.filter(function() {
309
                                return $(this).val().replace(/\s*/g, '') == '';
310
                         });
311
                     // if there are empty fields, then
312
                    if (empty.length) {
313
                            // add a CSS class name "error" for empty & required fields
314
                            empty.addClass("error");
315
                            // cancel seeking of the scrollable by returning false
316
                            return false;
317
                    // everything is good
318
                    } 
319
            }
320
            // update status bar
321
            $("#status li").removeClass("active").eq(i).addClass("active");
322
        // update confirm step
323
        if (api.getIndex()==0) {
324
            var image = $("input[type=radio][name=image-id]:checked");
325
            var imageRef = image.length ? image[0].id : false
326
            if (imageRef) {
327
                var imageName = $("label[for=" + imageRef + "] .image-title").text();
328
                $("#machine_image-label")[0].textContent = imageName;
329
                $("input[type=text][name=machine_name]")[0].value = "My " + imageName + " server";
330
            }
331
        } else if (api.getIndex()==1) {
332
            $("#machine_cpu-label")[0].textContent = $("#cpu-indicator")[0].value;
333
            $("#machine_ram-label")[0].textContent = $("#ram-indicator")[0].value;
334
            $("#machine_storage-label")[0].textContent = $("#storage-indicator")[0].value;
335
        }    
336
    });
337
    // if tab is pressed on the next button seek to next page
338
    $(root).live('keydown', function (e) {
339
       if ( e.keyCode == 9 ){
340
           if(e.preventDefault) {
341
               e.preventDefault();
342
           }
343
           api.next();
344
        }
345
    });
346
    $("#name").keypress(function (e) {
347
                if ((e.which && e.which == 13) || (e.keyCode && e.keyCode == 13)) {
348
                        $('#start').click();
349
                        return false;
350
                } else {
351
                        return true;
352
                }
353
    });
354
});
355

356
// disable sliders in flavor selection
357
function disableSliders() {
358
    $("#cpu").attr('disabled',true);
359
    $("#ram").attr('disabled',true);
360
    $("#storage").attr('disabled',true);
361
}
362

363
//update radio button when clicking on text
364
$("#small-body").live('click' ,function() { 
365
    $(this).parent().find("#small").click();
366
});
367
$("#medium-body").live('click' ,function() { 
368
    $(this).parent().find("#medium").click();
369
});
370
$("#large-body").live('click' ,function() { 
371
    $(this).parent().find("#large").click();
372
});
373
$("#custom-body").live('click' ,function() { 
374
    $(this).parent().find("#custom").click();
375
});
376

377
//select image div on radio button select
378
$('.radio').live('click' ,function() {           
379
    $(this).parents("div").find(".image").removeClass('selecteddiv');
380
    if($(this).is(':checked'))  {
381
        $(this).parent().addClass('selecteddiv');
382
    }
383
});
384

385
// confirm all actions
386
$("div.confirm_multiple .yes").live('click', function(){
387
    while(pending_actions.length > 0){ // if there is a pending action for this server execute it
388
        action = pending_actions.pop(); // extract action
389
        var serverID = action[1];
390
        if ($.cookie("list") != '1') { // standard view
391
            $('#' + serverID + ' .selected').removeClass('selected');
392
            $('#' + serverID + ' .display').removeClass('display');
393
            if (action[0] == shutdown) {
394
                $('#' + serverID + ' .status').text('Shutting down');
395
            } else if (action[0] == start) {
396
                $('#' + serverID + ' .status').text('Starting');
397
            } else if (action[0] == reboot) {
398
                $('#' + serverID + ' .status').text('Rebooting');
399
            } else if (action[0] == destroy) {
400
                $('#' + serverID + ' .status').text('Destroying');
401
            }
402
            $('#' + serverID + ' .spinner').show();
403
        } else { // list view
404
            osIcon = $('#'+serverID).parent().parent().find('.list-logo');
405
            osIcon.attr('os',osIcon.attr('src'));
406
            osIcon.attr('src','static/progress.gif');
407
            if (action[0] == shutdown) {
408
                $('#' + serverID).parent().parent().find('span.status').text('Shutting down');
409
            } else if (action[0] == start) {
410
                $('#' + serverID).parent().parent().find('span.status').text('Starting');
411
            } else if (action[0] == reboot) {
412
                $('#' + serverID).parent().parent().find('span.status').text('Rebooting');
413
            } else if (action[0] == destroy) {
414
                $('#' + serverID).parent().parent().find('span.status').text('Destroying');
415
            }
416
        }
417
        action[0]([serverID]); // execute action
418
    }
419
    update_confirmations();    
420
});
421

422
// cancel all actions
423
$("div.confirm_multiple .no").live('click', function(){
424
    pending_actions = [];
425
    $('.machine .selected').removeClass('selected');
426
    $('.machine .display').removeClass('display');
427
    update_confirmations();
428
});
429

430
// validate cpu input box
431
$("#cpu-indicator").live('change',function(){
432
    var v = Number(this.value);
433
    var i = cpus.indexOf(v);
434
    if (isNaN(v)) {
435
        $(this).value = cpus[0];
436
        $("#cpu").data('rangeinput').setValue(0);
437
    } else if (i == -1) {
438
        for (var j=0; j < cpus.length; j++)
439
            if (v<cpus[j])
440
                break;
441
        $("#cpu").data('rangeinput').setValue(j);
442
    } else {
443
        $("#cpu").data('rangeinput').setValue(i);
444
    }   
445
    return false;
446
});
447

448
// validate ram input box
449
$("#ram-indicator").live('change',function(){
450
    var v = Number(this.value);
451
    var i = ram.indexOf(v);
452
    if (isNaN(v)) {
453
        $(this).value = cpus[0];
454
        $("#ram").data('rangeinput').setValue(0);
455
    } else if (i == -1) {
456
        for (var j=0; j < ram.length; j++)
457
            if (v<ram[j])
458
                break;
459
        $("#ram").data('rangeinput').setValue(j);
460
    } else {
461
        $("#ram").data('rangeinput').setValue(i);
462
    }   
463
    return false;
464
});
465

466

467
// validate storage input box
468
$("#storage-indicator").live('change',function(){
469
    var v = Number(this.value);
470
    var i = disks.indexOf(v);
471
    if (isNaN(v)) {
472
        $(this).value = disks[0];
473
        $("#storage").data('rangeinput').setValue(0);
474
    } else if (i == -1) {
475
        for (var j=0; j < disks.length; j++)
476
            if (v<disks[j])
477
                break;
478
        $("#storage").data('rangeinput').setValue(j);
479
    } else {
480
        $("#storage").data('rangeinput').setValue(i);
481
    }   
482
    return false;
483
});
484

485
// selecting the small size
486
$("#small").click(function(){
487
    $("#cpu").data('rangeinput').setValue(0);
488
    $("#ram").data('rangeinput').setValue(0);
489
    $("#storage").data('rangeinput').setValue(0);
490
    $("#cpu-indicator")[0].value = cpus[0];
491
    $("#ram-indicator")[0].value = ram[0];
492
    $("#storage-indicator")[0].value = disks[0];
493
    $("#small").addClass("active");
494
    $("#medium").removeClass("active");    
495
    $("#large").removeClass("active");    
496
    $("#custom").removeClass("active");    
497
});
498

499
// selecting the medium size
500
$("#medium").click(function(){
501
    $("#cpu").data('rangeinput').setValue(1);
502
    $("#ram").data('rangeinput').setValue(1);
503
    $("#storage").data('rangeinput').setValue(1);
504
    $("#cpu-indicator")[0].value = cpus[1];
505
    $("#ram-indicator")[0].value = ram[1];
506
    $("#storage-indicator")[0].value = disks[1];  
507
    $("#medium").addClass("active");  
508
    $("#small").removeClass("active");    
509
    $("#large").removeClass("active");    
510
    $("#custom").removeClass("active");  
511
});
512

513
// selecting the large size
514
$("#large").click(function(){
515
    $("#cpu").data('rangeinput').setValue(2);
516
    $("#ram").data('rangeinput').setValue(2);
517
    $("#storage").data('rangeinput').setValue(2);
518
    $("#cpu-indicator")[0].value = cpus[2];
519
    $("#ram-indicator")[0].value = ram[2];
520
    $("#storage-indicator")[0].value = disks[2];   
521
    $("#large").addClass("active"); 
522
    $("#medium").removeClass("active");    
523
    $("#small").removeClass("active");    
524
    $("#custom").removeClass("active");  
525
});
526

527
// selecting the custom flavor enables the sliders
528
$("#custom").click(function(){
529
    $("#cpu").attr('disabled',false);
530
    $("#ram").attr('disabled',false);
531
    $("#storage").attr('disabled',false);
532
    $("strong.sliders").style = 'color: #778899;';
533
    $("#custom").addClass("active"); 
534
    $("#medium").removeClass("active");    
535
    $("#large").removeClass("active");    
536
    $("#small").removeClass("active");  
537
});
538

539
// exit the wizard
540
$("#cancel").click(function(){
541
    $("a#create").overlay().close();
542
});
543

544
// starting a new VM through the wizard
545
$("#start").click(function(){
546
    var imageRef = $('input[type=radio][name=image-id]:checked')[0].id.replace('img-radio-','');   
547
    var flavorRef = identify_flavor($("#cpu-indicator")[0].value, $("#storage-indicator")[0].value, $("#ram-indicator")[0].value);
548
    var machineName = $('input[name=machine_name]')[0].value;
549

550
    create_vm(machineName, imageRef, flavorRef);
551

552
    $('a#create').data('overlay').close();
553
    $("#emptymachineslist").hide();
554

555
    try{console.warn('creating ' + $("input[name=machine_name]")[0].value)} catch(err){}
556

557
    $("#wizard").hide();
558
});
559

560
// basic functions executed on page load
561
if (images.length > 0) {
562
    // populate image list
563
    update_wizard_images();
564
}
565
if (flavors.length > 0) {
566
    // configure flavors
567
    update_wizard_flavors(); 
568
}
569
// create tabs for main menu
570
$("ul.tabs").tabs("div.panes ul");
571

    
572
</script>