1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-25 15:45:23 +00:00

Merge remote-tracking branch 'retspen/master'

Conflicts:
	conf/requirements.txt
This commit is contained in:
Jan Krcmar 2016-04-21 13:34:27 +02:00
commit db1ab88f51
11 changed files with 456 additions and 415 deletions

View file

@ -1,5 +1,6 @@
Django==1.8.2 Django==1.8.11
websockify==0.7.0 websockify==0.8.0
gunicorn==19.3.0 gunicorn==19.3.0
libvirt-python==1.2.16 libvirt-python==1.3.2
http://github.com/retspen/retspen.github.io/raw/master/libxml2-python-2.9.1.tar.gz #http://github.com/retspen/retspen.github.io/raw/master/libxml2-python-2.9.1.tar.gz
http://git.gnome.org/browse/libxml2/snapshot/libxml2-2.9.1.tar.gz#egg=libxml2-python&subdirectory=python

View file

@ -0,0 +1,127 @@
{% load i18n %}
<html>
<head>
<meta charset="utf-8">
<link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="{{ STATIC_URL }}css/bootstrap.min.css">
<link href="{{ STATIC_URL }}css/webvirtcloud.css" rel="stylesheet">
<style>
body {
margin: 0;
padding: 0;
background-color: #313131;
}
.navbar {
margin-bottom: 2px;
}
#main_container {
padding: 0;
width: 100%;
max-width: none;
height: 100%;
background-color:#494949;
border-bottom-right-radius: 800px 600px;
}
#main_container canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
margin: auto;
}
#status {
z-index: 10000;
width: 80%;
position: absolute;
top: 5px;
left: 10%;
text-align: center;
}
</style>
{% block head %}{% endblock %}
</head>
<body>
<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
<div class="container">
<div class="navbar-header">
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand">{{ instance.name }}</a>
</div>
<div class="collapse navbar-collapse">
<ul class="nav navbar-nav">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">Send key(s) <span class="caret"></span></a>
<ul class="dropdown-menu" role="menu">
<li onclick='sendCtrlAltDel();'><a href='#'>Ctrl+Alt+Del</a></li>
<li class="divider"></li>
<li onclick='sendCtrlAltFN(0);'><a href='#'>Ctrl+Alt+F1</a></li>
<li onclick='sendCtrlAltFN(1);'><a href='#'>Ctrl+Alt+F2</a></li>
<li onclick='sendCtrlAltFN(2);'><a href='#'>Ctrl+Alt+F3</a></li>
<li onclick='sendCtrlAltFN(3);'><a href='#'>Ctrl+Alt+F4</a></li>
<li onclick='sendCtrlAltFN(4);'><a href='#'>Ctrl+Alt+F5</a></li>
<li onclick='sendCtrlAltFN(5);'><a href='#'>Ctrl+Alt+F6</a></li>
<li onclick='sendCtrlAltFN(6);'><a href='#'>Ctrl+Alt+F7</a></li>
<li onclick='sendCtrlAltFN(7);'><a href='#'>Ctrl+Alt+F8</a></li>
<li onclick='sendCtrlAltFN(8);'><a href='#'>Ctrl+Alt+F9</a></li>
<li onclick='sendCtrlAltFN(9);'><a href='#'>Ctrl+Alt+F10</a></li>
<li onclick='sendCtrlAltFN(10);'><a href='#'>Ctrl+Alt+F11</a></li>
<li onclick='sendCtrlAltFN(11);'><a href='#'>Ctrl+Alt+F12</a></li>
</ul>
</li>
<li onclick='fullscreen()'><a href='#'>{% trans "Fullscreen" %}</a></li>
{% block navbarmenu %}{% endblock %}
</ul>
</div>
</div>
</nav>
<div id='main_container' class="container">
{% block content %}{% endblock %}
</div>
<script src="{{ STATIC_URL }}js/jquery.js"></script>
<script src="{{ STATIC_URL }}js/bootstrap.min.js"></script>
<script>
function log_message(msg,type) {
var exist=$('#status').is('div');
status_div=$('<div id="status" class="alert alert-'+type+' role="alert"><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>'+msg+'</div>');
if (exist) {
$('#status').remove();
$('body').prepend(status_div);
}
else {
status_div.hide();
$('body').prepend(status_div);
status_div.fadeIn(200);
}
if (type!='danger') {
status_div.delay(3000).fadeOut(200);
}
}
function log_error(msg) {
log_message(msg,'danger');
}
function log_info(msg) {
log_message(msg,'info');
}
</script>
{% block foot %}{% endblock %}
</body>
</html>

View file

@ -1,157 +1,43 @@
{% extends "console-base.html" %}
{% load i18n %} {% load i18n %}
<html> {% load staticfiles %}
<head> {% block head %}
<link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico"> <script src="{% static "js/spice-html5/spicearraybuffer.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/spicearraybuffer.js"></script> <script src="{% static "js/spice-html5/enums.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/enums.js"></script> <script src="{% static "js/spice-html5/atKeynames.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/atKeynames.js"></script> <script src="{% static "js/spice-html5/utils.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/utils.js"></script> <script src="{% static "js/spice-html5/png.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/png.js"></script> <script src="{% static "js/spice-html5/lz.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/lz.js"></script> <script src="{% static "js/spice-html5/quic.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/quic.js"></script> <script src="{% static "js/spice-html5/bitmap.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/bitmap.js"></script> <script src="{% static "js/spice-html5/spicedataview.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/spicedataview.js"></script> <script src="{% static "js/spice-html5/spicetype.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/spicetype.js"></script> <script src="{% static "js/spice-html5/spicemsg.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/spicemsg.js"></script> <script src="{% static "js/spice-html5/wire.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/wire.js"></script> <script src="{% static "js/spice-html5/spiceconn.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/spiceconn.js"></script> <script src="{% static "js/spice-html5/display.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/display.js"></script> <script src="{% static "js/spice-html5/main.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/main.js"></script> <script src="{% static "js/spice-html5/inputs.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/inputs.js"></script> <script src="{% static "js/spice-html5/webm.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/webm.js"></script> <script src="{% static "js/spice-html5/playback.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/playback.js"></script> <script src="{% static "js/spice-html5/simulatecursor.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/simulatecursor.js"></script> <script src="{% static "js/spice-html5/cursor.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/cursor.js"></script> <script src="{% static "js/spice-html5/thirdparty/jsbn.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/thirdparty/jsbn.js"></script> <script src="{% static "js/spice-html5/thirdparty/rsa.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/thirdparty/rsa.js"></script> <script src="{% static "js/spice-html5/thirdparty/prng4.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/thirdparty/prng4.js"></script> <script src="{% static "js/spice-html5/thirdparty/rng.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/thirdparty/rng.js"></script> <script src="{% static "js/spice-html5/thirdparty/sha1.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/thirdparty/sha1.js"></script> <script src="{% static "js/spice-html5/ticket.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/ticket.js"></script> <script src="{% static "js/spice-html5/resize.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/resize.js"></script> <script src="{% static "js/spice-html5/filexfer.js" %}"></script>
<script src="{{ STATIC_URL }}js/spice-html5/filexfer.js"></script>
<style> {% endblock %}
body {
margin: 0;
padding: 0;
font-family: Helvetica;
background-color:#494949;
}
#status { {% block content %}
text-align: center; <div id='spice_container'></div>
width: 100%; {% endblock %}
margin: 0;
font-size: 1em;
height: 1.6em;
padding-top: 0.3em;
background-color: #222;
}
#spice-area {
border-bottom-right-radius: 800px 600px;
background-color: #313131;
height: 100%;
}
#spice-screen canvas {
padding-left: 0;
padding-right: 0;
margin-left: auto;
margin-right: auto;
display: block;
}
#spice-menu {
list-style-type: none;
margin: 0px;
padding: 0px;
border: 0px none;
position: absolute;
top: 0px;
z-index: 100;
}
#spice-menu li {
width: auto;
float: left;
margin: 2px;
padding: 0px;
border: 0px none;
position: relative;
height: 18px;
cursor: pointer;
padding: 0.2em;
background: #eee;
border-radius: 3px;
}
#spice-menu .spice-submenu {
display: none;
opacity: 0;
list-style-type: none;
margin: 0;
padding: 0;
border: 0;
overflow: hidden;
position: absolute;
}
#spice-menu .spice-submenu li {
float: none;
margin: 0;
padding: 0;
border: 0;
border-top: 1px solid white;
border-right: 1px solid white;
font: normal 14px sans-serif;
z-index: 100;
white-space: nowrap;
min-width: 100px;
padding: 0.2em;
border-radius: 0;
}
#spice-menu li:hover > .spice-submenu {
opacity: 1;
display: block;
margin: 2px 0 0 -2px;
}
#spice-menu li:hover > .spice-submenu li {
height: auto;
}
</style>
</head>
<body>
<div id="header">
<ul id='spice-menu'>
<li>Send key(s)
<ul class='spice-submenu'>
<li onclick='sendCtrlAltDel();'>Ctrl+Alt+Del</li>
<li onclick='sendCtrlAltFN(0);'>Ctrl+Alt+F1</li>
<li onclick='sendCtrlAltFN(1);'>Ctrl+Alt+F2</li>
<li onclick='sendCtrlAltFN(2);'>Ctrl+Alt+F3</li>
<li onclick='sendCtrlAltFN(3);'>Ctrl+Alt+F4</li>
<li onclick='sendCtrlAltFN(4);'>Ctrl+Alt+F5</li>
<li onclick='sendCtrlAltFN(5);'>Ctrl+Alt+F6</li>
<li onclick='sendCtrlAltFN(6);'>Ctrl+Alt+F7</li>
<li onclick='sendCtrlAltFN(7);'>Ctrl+Alt+F8</li>
<li onclick='sendCtrlAltFN(8);'>Ctrl+Alt+F9</li>
<li onclick='sendCtrlAltFN(9);'>Ctrl+Alt+F10</li>
<li onclick='sendCtrlAltFN(10);'>Ctrl+Alt+F11</li>
<li onclick='sendCtrlAltFN(11);'>Ctrl+Alt+F12</li>
</ul>
</li>
<li onclick='fullscreen()'>Fullscreen</li>
</ul>
<div id="status"></div>
</div>
<div id="spice-area">
<div id="spice-screen" class="spice-screen"></div>
</div>
{% block foot %}
<script> <script>
var sc; var sc;
@ -171,28 +57,6 @@
: defvalue; : defvalue;
} }
var status_div=false;
function log_message(msg,color,bgcolor) {
if (!status_div) {
status_div=document.getElementById('status');
}
status_div.innerHTML=msg;
if (color) {
status_div.style.color=color;
}
if (bgcolor) {
status_div.style.backgroundColor=bgcolor;
}
}
function log_error(msg) {
log_message(msg,'#000','#f44');
}
function log_info(msg) {
log_message(msg,'#000','#eee');
}
function spice_error(e) function spice_error(e)
{ {
console.log(e); console.log(e);
@ -224,7 +88,7 @@
try try
{ {
sc = new SpiceMainConn({uri: uri, password: password, screen_id: "spice-screen", sc = new SpiceMainConn({uri: uri, password: password, screen_id: "spice_container",
onsuccess: spice_success, onerror: spice_error, onagent: agent_connected }); onsuccess: spice_success, onerror: spice_error, onagent: agent_connected });
} }
catch (e) catch (e)
@ -259,7 +123,6 @@
} }
function agent_connected(sc) { function agent_connected(sc) {
console.log('Connected');
window.addEventListener('resize', handle_resize); window.addEventListener('resize', handle_resize);
window.spice_connection = this; window.spice_connection = this;
@ -278,7 +141,6 @@
console.log("File API is not supported"); console.log("File API is not supported");
log_info('Drag and drop transfer not supported.'); log_info('Drag and drop transfer not supported.');
} }
log_info('Connected');
} }
function sendCtrlAltFN(f) { function sendCtrlAltFN(f) {
@ -306,7 +168,7 @@
} }
function fullscreen() { function fullscreen() {
var screen=document.getElementById('spice-screen'); var screen=document.getElementById('spice_container');
if(screen.requestFullscreen) { if(screen.requestFullscreen) {
screen.requestFullscreen(); screen.requestFullscreen();
} else if(screen.mozRequestFullScreen) { } else if(screen.mozRequestFullScreen) {
@ -329,5 +191,4 @@
log_info('Connecting ...'); log_info('Connecting ...');
connect(uri,password); connect(uri,password);
</script> </script>
</body> {% endblock %}
</html>

View file

@ -1,26 +1,23 @@
{% extends "console-base.html" %}
{% load i18n %} {% load i18n %}
<html> {% load staticfiles %}
<head> {% block head %}
<link rel="shortcut icon" href="{{ STATIC_URL }}img/favicon.ico"> <script src="{% static "js/novnc/util.js" %}"></script>
<link rel="stylesheet" href="{{ STATIC_URL }}js/novnc/base.css" title="plain">
<!-- {% endblock %}
<script type='text/javascript'
src='http://getfirebug.com/releases/lite/1.2/firebug-lite-compressed.js'></script> {% block navbarmenu %}
-->
<script src="{{ STATIC_URL }}js/novnc/util.js"></script>
</head>
<body style="margin: 0px;">
<div id="noVNC_screen">
<div id="noVNC_status_bar" class="noVNC_status_bar" style="margin-top: 0px;">
<table border=0 width="100%">
<tr>
<td>
<div id="noVNC_status">{% trans "Loading..." %}</div>
</td>
<td width="32%" style="text-align:right;">
<div id="noVNC_buttons">
<!-- dirty fix for keyboard on iOS devices --> <!-- dirty fix for keyboard on iOS devices -->
<input type="button" id="showKeyboard" value="Keyboard" title="Show Keyboard"/> <li id="showKeyboard"><a href='#'>{% trans "Show Keyboad" %}</a></li>
{% endblock %}
{% block content %}
<div id='noVNC_area'>
<canvas id="noVNC_canvas" width="640px" height="20px">
{% trans "Canvas not supported." %}
</canvas>
</div>
<!-- Note that Google Chrome on Android doesn't respect any of these, <!-- Note that Google Chrome on Android doesn't respect any of these,
html attributes which attempt to disable text suggestions on the html attributes which attempt to disable text suggestions on the
on-screen keyboard. Let's hope Chrome implements the ime-mode on-screen keyboard. Let's hope Chrome implements the ime-mode
@ -29,20 +26,12 @@
<textarea id="keyboardinput" autocapitalize="off" <textarea id="keyboardinput" autocapitalize="off"
autocorrect="off" autocomplete="off" spellcheck="false" autocorrect="off" autocomplete="off" spellcheck="false"
mozactionhint="Enter" onsubmit="return false;" mozactionhint="Enter" onsubmit="return false;"
style="ime-mode: disabled;"> style="display: none;">
</textarea> </textarea>
<input type=button value="Ctrl+Alt+Del" id="sendCtrlAltDelButton"> {% endblock %}
<input type=button value="Fullscreen" id="askFullscreen">
</div> {% block foot %}
</td>
</tr>
</table>
</div>
<canvas id="noVNC_canvas" width="640px" height="20px">
{% trans "Canvas not supported." %}
</canvas>
</div>
<script> <script>
/*jslint white: false */ /*jslint white: false */
/*global window, $, Util, RFB, */ /*global window, $, Util, RFB, */
@ -60,18 +49,32 @@
var rfb; var rfb;
function passwordRequired(rfb) { function passwordRequired(rfb) {
var msg; var modal;
msg = '<form onsubmit="return setPassword();"'; modal = '<div class="modal fade">';
msg += 'role="form"'; modal += ' <div class="modal-dialog">';
msg += ' style="margin-bottom: 0px">'; modal += ' <div class="modal-content">';
msg += 'Password Required: '; modal += ' <div class="modal-header">';
msg += '<input type=password size=10 id="password_input" class="noVNC_status">'; modal += ' <h4 class="modal-title">{% trans "Password required" %}</h4>';
msg += '<\/form>'; modal += ' </div>';
$D('noVNC_status_bar').setAttribute("class", "noVNC_status_warn"); modal += ' <div class="modal-body">';
$D('noVNC_status').innerHTML = msg; modal += ' <form id="password_form" onsubmit="return setPassword();">';
modal += ' <div class="form-group">';
modal += ' <label for="password_input">Password</label>';
modal += ' <input type="password" class="form-control" id="password_input" placeholder="Password"/>';
modal += ' </div>';
modal += ' </form>';
modal += ' </div>';
modal += ' <div class="modal-footer">';
modal += ' <button type="button" class="btn btn-primary" data-dismiss="modal" onclick="return setPassword();">{% trans "OK" %}</button>';
modal += ' </div>';
modal += ' </div>';
modal += ' </div>';
modal += '</div>';
$('body').append(modal);
$('div.modal').modal();
} }
function setPassword() { function setPassword() {
rfb.sendPassword($D('password_input').value); rfb.sendPassword($('#password_input').val());
return false; return false;
} }
function sendCtrlAltDel() { function sendCtrlAltDel() {
@ -79,6 +82,19 @@
return false; return false;
} }
function sendCtrlAltFN(f) {
var keys_code=[0xFFBE,0xFFBF,0xFFC0,0xFFC1,0xFFC2,0xFFC3,0xFFC4,0xFFC5,0xFFC6,0xFFC7,0xFFC8,0xFFC9];
if (keys_code[f]==undefined) {
return;
}
rfb.sendKey(0xFFE3, 'down');
rfb.sendKey(0xFFE9, 'down');
rfb.sendKey(keys_code[f], 'down');
rfb.sendKey(keys_code[f], 'up');
rfb.sendKey(0xFFE9, 'up');
rfb.sendKey(0xFFE3, 'up');
};
// dirty fix for keyboard on iOS devices // dirty fix for keyboard on iOS devices
function showKeyboard() { function showKeyboard() {
var kbi, skb, l; var kbi, skb, l;
@ -103,48 +119,36 @@
function updateState(rfb, state, oldstate, msg) { function updateState(rfb, state, oldstate, msg) {
var s, sb, cad, af, level; var s, sb, cad, af, level;
s = $D('noVNC_status');
sb = $D('noVNC_status_bar');
cad = $D('sendCtrlAltDelButton'); cad = $D('sendCtrlAltDelButton');
af = $D('askFullscreen'); af = $D('askFullscreen');
switch (state) { switch (state) {
case 'failed': case 'failed':
level = "error"; level = "danger";
break; break;
case 'fatal': case 'fatal':
level = "error"; level = "danger";
break; break;
case 'normal': case 'normal':
level = "normal"; level = "info";
break; break;
case 'disconnected': case 'disconnected':
level = "normal"; level = "info";
break; break;
case 'loaded': case 'loaded':
level = "normal"; level = "info";
break; break;
default: default:
level = "warn"; level = "warning";
break; break;
} }
if (state === "normal") {
cad.disabled = false;
af.disabled = false;
}
else {
cad.disabled = true;
af.disabled = true;
}
if (typeof(msg) !== 'undefined') { if (typeof(msg) !== 'undefined') {
sb.setAttribute("class", "noVNC_status_" + level); log_message(msg,level);
s.innerHTML = msg;
} }
} }
function fullscreen() { function fullscreen() {
var screen=document.getElementById('noVNC_canvas'); var screen=document.getElementById('main_container');
if(screen.requestFullscreen) { if(screen.requestFullscreen) {
screen.requestFullscreen(); screen.requestFullscreen();
} else if(screen.mozRequestFullScreen) { } else if(screen.mozRequestFullScreen) {
@ -159,11 +163,6 @@
window.onscriptsload = function () { window.onscriptsload = function () {
var host, port, password, path, token; var host, port, password, path, token;
$D('sendCtrlAltDelButton').style.display = "inline";
$D('sendCtrlAltDelButton').onclick = sendCtrlAltDel;
$D('askFullscreen').style.display = "inline";
$D('askFullscreen').onclick = fullscreen;
// dirty fix for keyboard on iOS devices // dirty fix for keyboard on iOS devices
if (isTouchDevice) { if (isTouchDevice) {
$D('showKeyboard').onclick = showKeyboard; $D('showKeyboard').onclick = showKeyboard;
@ -188,7 +187,7 @@
return; return;
} }
rfb = new RFB({'target': $D('noVNC_canvas'), rfb = new RFB({'target': document.getElementById('noVNC_canvas'),
'encrypt': WebUtil.getQueryVar('encrypt', 'encrypt': WebUtil.getQueryVar('encrypt',
(window.location.protocol === "https:")), (window.location.protocol === "https:")),
'repeaterID': WebUtil.getQueryVar('repeaterID', ''), 'repeaterID': WebUtil.getQueryVar('repeaterID', ''),
@ -201,5 +200,4 @@
rfb.connect(host, port, password, path); rfb.connect(host, port, password, path);
}; };
</script> </script>
</body> {% endblock %}
</html>

View file

@ -40,6 +40,7 @@ class NewVMForm(forms.Form):
storage = forms.CharField(max_length=20, required=False) storage = forms.CharField(max_length=20, required=False)
template = forms.CharField(required=False) template = forms.CharField(required=False)
images = forms.CharField(required=False) images = forms.CharField(required=False)
cache_mode = forms.CharField(error_messages={'required': _('Please select HDD cache mode')})
hdd_size = forms.IntegerField(required=False) hdd_size = forms.IntegerField(required=False)
meta_prealloc = forms.BooleanField(required=False) meta_prealloc = forms.BooleanField(required=False)
virtio = forms.BooleanField(required=False) virtio = forms.BooleanField(required=False)

View file

@ -77,6 +77,23 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group meta-prealloc">
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="meta_prealloc" title="Metadata preallocation" value="true">
</div>
<label class="col-lg-1 control-label">{% trans "Image" %}</label>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "HDD cache mode" %}</label>
<div class="col-sm-6">
<select id="cache_mode" name="cache_mode" class="form-control">
{% for mode, name in cache_modes %}
<option value="{{ mode }}">{% trans name %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Network" %}</label> <label class="col-sm-3 control-label">{% trans "Network" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
@ -159,6 +176,16 @@
</div> </div>
<label class="col-lg-1 control-label">{% trans "Image" %}</label> <label class="col-lg-1 control-label">{% trans "Image" %}</label>
</div> </div>
<div class="form-group">
<label class="col-sm-3 control-label">{% trans "HDD cache mode" %}</label>
<div class="col-sm-6">
<select id="cache_mode" name="cache_mode" class="form-control">
{% for mode, name in cache_modes %}
<option value="{{ mode }}">{% trans name %}</option>
{% endfor %}
</select>
</div>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Network" %}</label> <label class="col-sm-3 control-label">{% trans "Network" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
@ -258,6 +285,7 @@
<label class="col-sm-3 control-label">{% trans "Storage" %}</label> <label class="col-sm-3 control-label">{% trans "Storage" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">
<input type="hidden" name="cache_mode" value="default">
<select name="storage" class="form-control"> <select name="storage" class="form-control">
{% if storages %} {% if storages %}
{% for storage in storages %} {% for storage in storages %}
@ -269,13 +297,6 @@
</select> </select>
</div> </div>
</div> </div>
<div class="form-group meta-prealloc">
<label class="col-sm-3 control-label">{% trans "Metadata" %}</label>
<div class="col-sm-6">
<input type="checkbox" name="meta_prealloc" title="Metadata preallocation" value="true">
</div>
<label class="col-lg-1 control-label">{% trans "Image" %}</label>
</div>
<div class="form-group"> <div class="form-group">
<label class="col-sm-3 control-label">{% trans "Network" %}</label> <label class="col-sm-3 control-label">{% trans "Network" %}</label>
<div class="col-sm-6"> <div class="col-sm-6">

View file

@ -41,6 +41,7 @@ def create_instance(request, compute_id):
networks = sorted(conn.get_networks()) networks = sorted(conn.get_networks())
instances = conn.get_instances() instances = conn.get_instances()
get_images = sorted(conn.get_storages_images()) get_images = sorted(conn.get_storages_images())
cache_modes = sorted(conn.get_cache_modes().items())
mac_auto = util.randomMAC() mac_auto = util.randomMAC()
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err) error_messages.append(lib_err)
@ -122,11 +123,15 @@ def create_instance(request, compute_id):
volumes[path] = conn.get_volume_type(path) volumes[path] = conn.get_volume_type(path)
except libvirtError as lib_err: except libvirtError as lib_err:
error_messages.append(lib_err.message) error_messages.append(lib_err.message)
if data['cache_mode'] not in conn.get_cache_modes():
error_msg = _("Invalid cache mode")
error_messages.append(error_msg)
if not error_messages: if not error_messages:
uuid = util.randomUUID() uuid = util.randomUUID()
try: try:
conn.create_instance(data['name'], data['memory'], data['vcpu'], data['host_model'], conn.create_instance(data['name'], data['memory'], data['vcpu'], data['host_model'],
uuid, volumes, data['networks'], data['virtio'], data['mac']) uuid, volumes, data['cache_mode'], data['networks'], data['virtio'],
data['mac'])
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid) create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
create_instance.save() create_instance.save()
return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']])) return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']]))

View file

@ -7,9 +7,17 @@ from webvirtcloud.settings import QEMU_CONSOLE_DEFAULT_TYPE
def get_rbd_storage_data(stg): def get_rbd_storage_data(stg):
xml = stg.XMLDesc(0) xml = stg.XMLDesc(0)
ceph_user = util.get_xml_path(xml, "/pool/source/auth/@username") ceph_user = util.get_xml_path(xml, "/pool/source/auth/@username")
ceph_host = util.get_xml_path(xml, "/pool/source/host/@name")
secrt_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid") def get_ceph_hosts(ctx):
return ceph_user, secrt_uuid, ceph_host hosts = []
for host in ctx.xpathEval("/pool/source/host"):
name = host.prop("name")
if name:
hosts.append({'name': name, 'port': host.prop("port")})
return hosts
ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts)
secret_uuid = util.get_xml_path(xml, "/pool/source/auth/secret/@uuid")
return ceph_user, secret_uuid, ceph_hosts
class wvmCreate(wvmConnect): class wvmCreate(wvmConnect):
@ -40,6 +48,17 @@ class wvmCreate(wvmConnect):
"""Get guest capabilities""" """Get guest capabilities"""
return util.get_xml_path(self.get_cap_xml(), "/capabilities/host/cpu/arch") return util.get_xml_path(self.get_cap_xml(), "/capabilities/host/cpu/arch")
def get_cache_modes(self):
"""Get cache available modes"""
return {
'default': 'Default',
'none': 'Disabled',
'writethrough': 'Write through',
'writeback': 'Write back',
'directsync': 'Direct sync', # since libvirt 0.9.5
'unsafe': 'Unsafe', # since libvirt 0.9.7
}
def create_volume(self, storage, name, size, format='qcow2', metadata=False): def create_volume(self, storage, name, size, format='qcow2', metadata=False):
size = int(size) * 1073741824 size = int(size) * 1073741824
stg = self.get_storage(storage) stg = self.get_storage(storage)
@ -121,7 +140,7 @@ class wvmCreate(wvmConnect):
vol = self.get_volume_by_path(path) vol = self.get_volume_by_path(path)
vol.delete() vol.delete()
def create_instance(self, name, memory, vcpu, host_model, uuid, images, networks, virtio, mac=None): def create_instance(self, name, memory, vcpu, host_model, uuid, images, cache_mode, networks, virtio, mac=None):
""" """
Create VM function Create VM function
""" """
@ -162,19 +181,27 @@ class wvmCreate(wvmConnect):
stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type") stg_type = util.get_xml_path(stg.XMLDesc(0), "/pool/@type")
if stg_type == 'rbd': if stg_type == 'rbd':
ceph_user, secrt_uuid, ceph_host = get_rbd_storage_data(stg) ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg)
xml += """<disk type='network' device='disk'> xml += """<disk type='network' device='disk'>
<driver name='qemu' type='%s'/> <driver name='qemu' type='%s' cache='%s'/>
<auth username='%s'> <auth username='%s'>
<secret type='ceph' uuid='%s'/> <secret type='ceph' uuid='%s'/>
</auth> </auth>
<source protocol='rbd' name='%s'> <source protocol='rbd' name='%s'>""" % (img_type, cache_mode, ceph_user, secret_uuid, image)
<host name='%s' port='6789'/> if isinstance(ceph_hosts, list):
</source>""" % (img_type, ceph_user, secrt_uuid, image, ceph_host) for host in ceph_hosts:
if host.get('port'):
xml += """
<host name='%s' port='%s'/>""" % (host.get('name'), host.get('port'))
else:
xml += """
<host name='%s'/>""" % host.get('name')
xml += """
</source>"""
else: else:
xml += """<disk type='file' device='disk'> xml += """<disk type='file' device='disk'>
<driver name='qemu' type='%s'/> <driver name='qemu' type='%s' cache='%s'/>
<source file='%s'/>""" % (img_type, image) <source file='%s'/>""" % (img_type, cache_mode, image)
if virtio: if virtio:
xml += """<target dev='vd%s' bus='virtio'/>""" % (disk_letters.pop(0),) xml += """<target dev='vd%s' bus='virtio'/>""" % (disk_letters.pop(0),)