root / ui / templates / machines.html @ 6902f72e
History | View | Annotate | Download (16.7 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">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 |
<span class="view-separator">|</span> |
15 |
<a id="list" href="/machines/list">=</a> |
16 |
</div>
|
17 |
|
18 |
<div id="emptymachineslist"><h1 id="welcomeheader">{% trans "Welcome to the ocean!" %}</h1><br /> |
19 |
<span class="welcomebody">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="#">tour</a>.</span><br /><br /> |
20 |
<span class="welcomebody">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">For more information or text, click <a href="#">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"><strong>1.</strong> {% trans "Image" %}</li> |
31 |
<li><strong>2.</strong> {% trans "Machine" %}</li> |
32 |
<li><strong>3.</strong> {% trans "Review" %}</li> |
33 |
</ul>
|
34 |
<!-- scrollable items -->
|
35 |
<div class="items"> |
36 |
<!-- pages -->
|
37 |
<div class="page"> |
38 |
<h2>{% trans "Select an OS" %}</h2> |
39 |
<ul class="tabs"> |
40 |
<li><a href="#">{% trans "standard" %}</a></li> |
41 |
<li><a href="#">{% trans "custom" %}</a></li> |
42 |
</ul>
|
43 |
<div class="panes"> |
44 |
<li id="image-template" style="display:none"> |
45 |
<label for="image.id"> |
46 |
<a>
|
47 |
<div class="image"> |
48 |
<img src="" class="image-logo"/> |
49 |
<strong class="image-title">image.title</strong> |
50 |
<input class="radio" type="radio" name="image-id" id="image-id" /> |
51 |
<br /> |
52 |
<span class="description">image.description</span> |
53 |
<span class="size">?? MB</span> |
54 |
</div>
|
55 |
</a>
|
56 |
</label>
|
57 |
</li>
|
58 |
<ul class="pane" id="standard-images"> |
59 |
<!-- standard images -->
|
60 |
</ul>
|
61 |
<ul class="pane" id="custom-images"> |
62 |
<!-- custom images -->
|
63 |
</ul>
|
64 |
</div>
|
65 |
<button type="button" class="prev" id="cancel">{% trans "Cancel" %}</button> |
66 |
<button type="button" class="next right">{% trans "Next" %} »</button> |
67 |
</div>
|
68 |
<div class="page"> |
69 |
<h2>{% trans "Select CPU, RAM and storage" %}</h2> |
70 |
<ul>
|
71 |
<li>
|
72 |
<div class="machine-type"> |
73 |
<label for="small"> |
74 |
<input type="radio" id="small" name="machine-type" value="small" checked="true" /> |
75 |
<strong>{% trans "small" %}</strong> |
76 |
</label>
|
77 |
</div>
|
78 |
<div class="machine-type"> |
79 |
<label for="medium"> |
80 |
<input type="radio" id="medium" name="machine-type" value="medium" /> |
81 |
<strong>{% trans "medium" %}</strong> |
82 |
</label>
|
83 |
</div>
|
84 |
<div class="machine-type"> |
85 |
<label for="large"> |
86 |
<input type="radio" id="large" name="machine-type" value="large" /> |
87 |
<strong>{% trans "large" %}</strong> |
88 |
</label>
|
89 |
</div>
|
90 |
<div class="machine-type"> |
91 |
<label for="custom"> |
92 |
<input type="radio" name="machine-type" id="custom" value="large" /> |
93 |
<strong>{% trans "custom" %}</strong> |
94 |
</label>
|
95 |
</div>
|
96 |
</li>
|
97 |
<li>
|
98 |
<label><strong class="sliders">CPU (cores)</strong></label> |
99 |
<input type="range" id="cpu" style="display:none" /> |
100 |
<input type="text" class="range" id="cpu-indicator" /> |
101 |
</li>
|
102 |
<li>
|
103 |
<label><strong class="sliders">RAM (MB)</strong></label> |
104 |
<input type="range" id="ram" style="display:none" /> |
105 |
<input type="text" class="range" id="ram-indicator" /> |
106 |
|
107 |
</li>
|
108 |
<li>
|
109 |
<label><strong class="sliders">Storage (GB)</strong></label> |
110 |
<input type="range" id="storage" style="display:none" /> |
111 |
<input type="text" class="range" id="storage-indicator" /> |
112 |
|
113 |
</li>
|
114 |
<li>
|
115 |
<div class="cost"> |
116 |
{% trans "Cost per hour:" %} 20 {% trans "credits" %} | {% trans "Credits currently in account:" %} 10.000 |
117 |
</div>
|
118 |
</li>
|
119 |
</ul>
|
120 |
<button type="button" class="prev">« {% trans "Back" %}</button> |
121 |
<button type="button" class="next right">{% trans "Next" %} »</button> |
122 |
</div>
|
123 |
<div class="page"> |
124 |
<h2>{% trans "Confirm your settings" %}</h2> |
125 |
<ul>
|
126 |
<li class="required"> |
127 |
<label>
|
128 |
<strong>Machine name</strong> |
129 |
<input type="text" class="text" name="machine_name" value="My Ubuntu 10.04 x86_64 server"/> |
130 |
</label>
|
131 |
</li>
|
132 |
<li>
|
133 |
<strong>{% trans "Image:" %}</strong> <span id="machine_image-label">Ubuntu 10.04 x86_64 server</span> |
134 |
</li>
|
135 |
<li>
|
136 |
<strong>{% trans "CPU:" %}</strong> <span id="machine_cpu-label">2</span> <span>{% trans "cores" %}</span> |
137 |
</li>
|
138 |
<li>
|
139 |
<strong>{% trans "RAM:" %}</strong> <span id="machine_ram-label">1024</span><span>MB</span> |
140 |
</li>
|
141 |
<li>
|
142 |
<strong>{% trans "Storage:" %}</strong> <span id="machine_storage-label">10</span><span>GB</span> |
143 |
</li>
|
144 |
<li>
|
145 |
<strong>{% trans "Cost per hour:" %}</strong> <span>20 {% trans "credits" %}</span> |
146 |
</li>
|
147 |
<li>
|
148 |
<strong>{% trans "Remaining credits:" %}</strong> <span>10.000</span> |
149 |
</li>
|
150 |
</ul>
|
151 |
<button type="button" class="prev">« {% trans "Back" %}</button> |
152 |
<button type="button" class="next right" id="start">{% trans "Create VM" %}</button> |
153 |
</div>
|
154 |
</div>
|
155 |
</div>
|
156 |
</form>
|
157 |
|
158 |
<!-- notification after wizard completion -->
|
159 |
<a id="notification" rel="#error-success" href="#"></a> |
160 |
|
161 |
<div class="modal" id="error-success"> |
162 |
<h3>{% trans "Error!/Success!" %}</h3> |
163 |
<div><p>{% trans "More details about the result"%}</p></div> |
164 |
</div>
|
165 |
|
166 |
<!-- confirmation before executing an action -->
|
167 |
<a id="confirmation" rel="#yes-no" href="#"></a> |
168 |
|
169 |
<div class="modal" id="yes-no"> |
170 |
<h3>{% trans "You are about to xxx machine yyy" %}</h3> |
171 |
<p>{% trans "Are you sure you want to proceed?" %}</p> |
172 |
<button>{% trans "Yes" %}</button> |
173 |
<button>{% trans "No" %}</button> |
174 |
</div>
|
175 |
|
176 |
<div id="machinesview"></div> |
177 |
|
178 |
<div class="confirm_multiple"> |
179 |
<p>{% trans "Your actions will affect" %} <span class="actionLen">XX</span> {% trans "machines" %}</p> |
180 |
<button class="yes">{% trans "Confirm All" %}</button> |
181 |
<button class="no">{% trans "Cancel All" %}</button> |
182 |
</div>
|
183 |
|
184 |
<div id="machines" class="separator"></div> |
185 |
|
186 |
<script>
|
187 |
// hardcoded image types
|
188 |
// TODO: get this from the metadata
|
189 |
var image_tags = {
|
190 |
1: 'archlinux',
|
191 |
2: 'centos',
|
192 |
3: 'debian',
|
193 |
4: 'freebsd',
|
194 |
5: 'gentoo',
|
195 |
6: 'netbsd',
|
196 |
7: 'openbsd',
|
197 |
8: 'redhat',
|
198 |
9: 'slackware',
|
199 |
10: 'suse',
|
200 |
11: 'ubuntu',
|
201 |
12: 'windows',
|
202 |
20: 'ubuntu',
|
203 |
};
|
204 |
|
205 |
// switch to list view
|
206 |
$("a#list").click(function(){
|
207 |
list_view();
|
208 |
return false;
|
209 |
});
|
210 |
|
211 |
// switch to standard view
|
212 |
$("a#standard").click(function(){
|
213 |
standard_view();
|
214 |
return false;
|
215 |
});
|
216 |
|
217 |
// launch VM creation wizard
|
218 |
$("a#create").click(function(){
|
219 |
// launch wizard only if images and flavors are found
|
220 |
if (images.length > 0 && flavors.length > 0) {
|
221 |
$("#wizard").scrollable().begin();
|
222 |
$("#wizard").show();
|
223 |
$('a#create').data('overlay').load()
|
224 |
} else if (images.length == 0 ) {
|
225 |
ajax_error('NO_IMAGES');
|
226 |
return false;
|
227 |
} else if (flavors.length == 0) {
|
228 |
ajax_error('NO_FLAVORS');
|
229 |
return false;
|
230 |
}
|
231 |
});
|
232 |
|
233 |
// create wizard overlay
|
234 |
$(function() {
|
235 |
$("a#create").overlay({
|
236 |
mask: '#000',
|
237 |
effect: 'default',
|
238 |
top: '5%',
|
239 |
oneInstance: false,
|
240 |
closeOnClick: false
|
241 |
});
|
242 |
});
|
243 |
|
244 |
// wizard
|
245 |
$(function() {
|
246 |
var root = $("#wizard").scrollable();
|
247 |
var api = root.scrollable();
|
248 |
// rangeinput with default configuration
|
249 |
// validation logic is done inside the onBeforeSeek callback
|
250 |
api.onBeforeSeek(function(event, i) {
|
251 |
// we are going 1 step backwards so no need for validation
|
252 |
if (api.getIndex() < i) {
|
253 |
// 1. get current page
|
254 |
var page = root.find(".page").eq(api.getIndex()),
|
255 |
// 2. .. and all required fields inside the page
|
256 |
inputs = page.find(".required :input").removeClass("error"),
|
257 |
// 3. .. which are empty
|
258 |
empty = inputs.filter(function() {
|
259 |
return $(this).val().replace(/\s*/g, '') == '';
|
260 |
});
|
261 |
// if there are empty fields, then
|
262 |
if (empty.length) {
|
263 |
// add a CSS class name "error" for empty & required fields
|
264 |
empty.addClass("error");
|
265 |
// cancel seeking of the scrollable by returning false
|
266 |
return false;
|
267 |
// everything is good
|
268 |
}
|
269 |
}
|
270 |
// update status bar
|
271 |
$("#status li").removeClass("active").eq(i).addClass("active");
|
272 |
// update confirm step
|
273 |
if (api.getIndex()==0) {
|
274 |
var image = $("input[type=radio][name=image-id]:checked");
|
275 |
var imageRef = image.length ? image[0].id : false
|
276 |
if (imageRef) {
|
277 |
var imageName = $("label[for=" + imageRef + "] .image-title").text();
|
278 |
$("#machine_image-label")[0].textContent = imageName;
|
279 |
$("input[type=text][name=machine_name]")[0].value = "My " + imageName + " server";
|
280 |
}
|
281 |
} else if (api.getIndex()==1) {
|
282 |
$("#machine_cpu-label")[0].textContent = $("#cpu-indicator")[0].value;
|
283 |
$("#machine_ram-label")[0].textContent = $("#ram-indicator")[0].value;
|
284 |
$("#machine_storage-label")[0].textContent = $("#storage-indicator")[0].value;
|
285 |
}
|
286 |
});
|
287 |
// if tab is pressed on the next button seek to next page
|
288 |
root.find("button.next").keydown(function(e) {
|
289 |
if (e.keyCode == 9) {
|
290 |
// seeks to next tab by executing our validation routine
|
291 |
api.next();
|
292 |
e.preventDefault();
|
293 |
}
|
294 |
});
|
295 |
});
|
296 |
|
297 |
// disable sliders in flavor selection
|
298 |
function disableSliders() {
|
299 |
$("#cpu").attr('disabled',true);
|
300 |
$("#ram").attr('disabled',true);
|
301 |
$("#storage").attr('disabled',true);
|
302 |
}
|
303 |
|
304 |
// confirm all actions
|
305 |
$("div.confirm_multiple .yes").live('click', function(){
|
306 |
while(pending_actions.length > 0){ // if there is a pending action for this server execute it
|
307 |
action = pending_actions.pop(); // extract action
|
308 |
var serverID = action[1];
|
309 |
|
310 |
if ($.cookie("list") != '1') { // standard view
|
311 |
$('#'+serverID+' .spinner').show();
|
312 |
$('#'+serverID+' .selected').removeClass('selected');
|
313 |
$('#'+serverID+' .display').removeClass('display');
|
314 |
} else { // list view
|
315 |
osIcon = $('#'+serverID).parent().parent().find('.list-logo');
|
316 |
osIcon.attr('os',osIcon.attr('src'));
|
317 |
osIcon.attr('src','static/progress.gif');
|
318 |
}
|
319 |
action[0]([serverID]); // execute action
|
320 |
}
|
321 |
update_confirmations();
|
322 |
});
|
323 |
|
324 |
// cancel all actions
|
325 |
$("div.confirm_multiple .no").live('click', function(){
|
326 |
pending_actions = [];
|
327 |
$('.machine .selected').removeClass('selected');
|
328 |
$('.machine .display').removeClass('display');
|
329 |
update_confirmations();
|
330 |
});
|
331 |
|
332 |
// validate cpu input box
|
333 |
$("#cpu-indicator").live('change',function(){
|
334 |
var v = Number(this.value);
|
335 |
var i = cpus.indexOf(v);
|
336 |
if (isNaN(v)) {
|
337 |
$(this).value = cpus[0];
|
338 |
$("#cpu").data('rangeinput').setValue(0);
|
339 |
} else if (i == -1) {
|
340 |
for (var j=0; j < cpus.length; j++)
|
341 |
if (v<cpus[j])
|
342 |
break;
|
343 |
$("#cpu").data('rangeinput').setValue(j);
|
344 |
} else {
|
345 |
$("#cpu").data('rangeinput').setValue(i);
|
346 |
}
|
347 |
return false;
|
348 |
});
|
349 |
|
350 |
// validate ram input box
|
351 |
$("#ram-indicator").live('change',function(){
|
352 |
var v = Number(this.value);
|
353 |
var i = ram.indexOf(v);
|
354 |
if (isNaN(v)) {
|
355 |
$(this).value = cpus[0];
|
356 |
$("#ram").data('rangeinput').setValue(0);
|
357 |
} else if (i == -1) {
|
358 |
for (var j=0; j < ram.length; j++)
|
359 |
if (v<ram[j])
|
360 |
break;
|
361 |
$("#ram").data('rangeinput').setValue(j);
|
362 |
} else {
|
363 |
$("#ram").data('rangeinput').setValue(i);
|
364 |
}
|
365 |
return false;
|
366 |
});
|
367 |
|
368 |
|
369 |
// validate storage input box
|
370 |
$("#storage-indicator").live('change',function(){
|
371 |
var v = Number(this.value);
|
372 |
var i = disks.indexOf(v);
|
373 |
if (isNaN(v)) {
|
374 |
$(this).value = disks[0];
|
375 |
$("#storage").data('rangeinput').setValue(0);
|
376 |
} else if (i == -1) {
|
377 |
for (var j=0; j < disks.length; j++)
|
378 |
if (v<disks[j])
|
379 |
break;
|
380 |
$("#storage").data('rangeinput').setValue(j);
|
381 |
} else {
|
382 |
$("#storage").data('rangeinput').setValue(i);
|
383 |
}
|
384 |
return false;
|
385 |
});
|
386 |
|
387 |
// selecting the small size
|
388 |
$("#small").click(function(){
|
389 |
$("#cpu").data('rangeinput').setValue(0);
|
390 |
$("#ram").data('rangeinput').setValue(0);
|
391 |
$("#storage").data('rangeinput').setValue(0);
|
392 |
$("#cpu-indicator")[0].value = cpus[0];
|
393 |
$("#ram-indicator")[0].value = ram[0];
|
394 |
$("#storage-indicator")[0].value = disks[0];
|
395 |
});
|
396 |
|
397 |
// selecting the medium size
|
398 |
$("#medium").click(function(){
|
399 |
$("#cpu").data('rangeinput').setValue(1);
|
400 |
$("#ram").data('rangeinput').setValue(1);
|
401 |
$("#storage").data('rangeinput').setValue(1);
|
402 |
$("#cpu-indicator")[0].value = cpus[1];
|
403 |
$("#ram-indicator")[0].value = ram[1];
|
404 |
$("#storage-indicator")[0].value = disks[1];
|
405 |
});
|
406 |
|
407 |
// selecting the large size
|
408 |
$("#large").click(function(){
|
409 |
$("#cpu").data('rangeinput').setValue(2);
|
410 |
$("#ram").data('rangeinput').setValue(2);
|
411 |
$("#storage").data('rangeinput').setValue(2);
|
412 |
$("#cpu-indicator")[0].value = cpus[2];
|
413 |
$("#ram-indicator")[0].value = ram[2];
|
414 |
$("#storage-indicator")[0].value = disks[2];
|
415 |
});
|
416 |
|
417 |
// selecting the custom flavor enables the sliders
|
418 |
$("#custom").click(function(){
|
419 |
$("#cpu").attr('disabled',false);
|
420 |
$("#ram").attr('disabled',false);
|
421 |
$("#storage").attr('disabled',false);
|
422 |
$("strong.sliders").style = 'color: #778899;';
|
423 |
});
|
424 |
|
425 |
// exit the wizard
|
426 |
$("#cancel").click(function(){
|
427 |
$("a#create").overlay().close();
|
428 |
});
|
429 |
|
430 |
// starting a new VM through the wizard
|
431 |
$("#start").click(function(){
|
432 |
var imageRef = $('input[type=radio][name=image-id]:checked')[0].id.replace('img-radio-','');
|
433 |
var flavorRef = identify_flavor($("#cpu-indicator")[0].value, $("#storage-indicator")[0].value, $("#ram-indicator")[0].value);
|
434 |
var machineName = $('input[name=machine_name]')[0].value;
|
435 |
|
436 |
create_vm(machineName, imageRef, flavorRef);
|
437 |
|
438 |
$('a#create').data('overlay').close();
|
439 |
$("#emptymachineslist").hide();
|
440 |
|
441 |
try{console.warn('creating ' + $("input[name=machine_name]")[0].value)} catch(err){}
|
442 |
|
443 |
$("#wizard").hide();
|
444 |
});
|
445 |
|
446 |
// basic functions executed on page load
|
447 |
if (images.length > 0) {
|
448 |
// populate image list
|
449 |
update_wizard_images();
|
450 |
}
|
451 |
if (flavors.length > 0) {
|
452 |
// configure flavors
|
453 |
update_wizard_flavors();
|
454 |
}
|
455 |
// create tabs for main menu
|
456 |
$("ul.tabs").tabs("div.panes ul");
|
457 |
|
458 |
</script>
|