mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 23:25:24 +00:00
commit
3bae40c8aa
15 changed files with 494 additions and 226 deletions
|
@ -53,7 +53,7 @@
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<nav class="navbar navbar-inverse navbar-static-top" role="navigation">
|
<nav class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="navbar-header">
|
<div class="navbar-header">
|
||||||
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target=".navbar-collapse">
|
||||||
|
|
|
@ -80,7 +80,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="noVNC_fallback_error" class="noVNC_center">
|
<div id="noVNC_fallback_error" class="noVNC_center">
|
||||||
<div>
|
<div>
|
||||||
<div>noVNC encountered an error:</div>
|
<div>{% trans 'noVNC encountered an error' %}:</div>
|
||||||
<br>
|
<br>
|
||||||
<div id="noVNC_fallback_errormsg"></div>
|
<div id="noVNC_fallback_errormsg"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -294,7 +294,7 @@
|
||||||
{% block content %}
|
{% block content %}
|
||||||
<div id="noVNC_status_bar">
|
<div id="noVNC_status_bar">
|
||||||
<div id="noVNC_left_dummy_elem"></div>
|
<div id="noVNC_left_dummy_elem"></div>
|
||||||
<div id="noVNC_status">Loading</div>
|
<div id="noVNC_status">{% trans 'Loading' %}</div>
|
||||||
<div id="noVNC_buttons">
|
<div id="noVNC_buttons">
|
||||||
<input type=button value="Send CtrlAltDel" id="sendCtrlAltDelButton" class="noVNC_shown">
|
<input type=button value="Send CtrlAltDel" id="sendCtrlAltDelButton" class="noVNC_shown">
|
||||||
<span id="noVNC_power_buttons" class="noVNC_hidden">
|
<span id="noVNC_power_buttons" class="noVNC_hidden">
|
||||||
|
|
|
@ -43,7 +43,7 @@ def create_instance(request, compute_id):
|
||||||
compute.type)
|
compute.type)
|
||||||
|
|
||||||
instances = conn.get_instances()
|
instances = conn.get_instances()
|
||||||
videos = conn.get_video()
|
videos = conn.get_video_models()
|
||||||
cache_modes = sorted(conn.get_cache_modes().items())
|
cache_modes = sorted(conn.get_cache_modes().items())
|
||||||
default_cache = INSTANCE_VOLUME_DEFAULT_CACHE
|
default_cache = INSTANCE_VOLUME_DEFAULT_CACHE
|
||||||
listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES
|
listener_addr = QEMU_CONSOLE_LISTEN_ADDRESSES
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
#cloud-config
|
#cloud-config
|
||||||
{% if instance_keys %}
|
{% if instance_keys %}
|
||||||
ssh_authorized_keys:
|
ssh_authorized_keys:
|
||||||
{% for key in instance_keys %} - {{ key }}{% endfor %}
|
{% for key in instance_keys %} - {{ key }}
|
||||||
|
{% endfor %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
|
|
|
@ -432,11 +432,7 @@
|
||||||
<small><input type="checkbox" class="js-custom__checkbox" /> {% trans "Custom value" %}</small>
|
<small><input type="checkbox" class="js-custom__checkbox" /> {% trans "Custom value" %}</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% ifequal status 5 %}
|
<button type="submit" class="btn btn-lg btn-success pull-right" name="resizevm_mem">{% trans "Resize" %}</button>
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="resizevm_mem">{% trans "Resize" %}</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled">{% trans "Resize" %}</button>
|
|
||||||
{% endifequal %}
|
|
||||||
</form>
|
</form>
|
||||||
{% else %}
|
{% else %}
|
||||||
{% trans "You don't have permission for resizing instance" %}
|
{% trans "You don't have permission for resizing instance" %}
|
||||||
|
@ -851,53 +847,138 @@
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<div class="col-xs-12 col-sm-12">
|
<div class="col-xs-12 col-sm-12">
|
||||||
<form method="post" role="form">{% csrf_token %}
|
<p><strong>{% trans "Network Devices" %}</strong></p>
|
||||||
{% for network in networks %}
|
<table class="table table-hover">
|
||||||
{% if forloop.first %}
|
<thead>
|
||||||
<p><strong>{% trans "Network Devices" %}</strong></p>
|
<tr>
|
||||||
{% endif %}
|
<th>{% trans 'Name' %}</th>
|
||||||
<div class="panel panel-default">
|
<th>{% trans 'MAC' %}</th>
|
||||||
<div class="panel-heading">
|
<th>{% trans 'NIC' %}</th>
|
||||||
<label>eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</label>
|
<th>{% trans 'Filter' %}</th>
|
||||||
<button class="btn btn-sm pull-right btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete Device" %}" onclick="return confirm('{% trans "Are you sure?" %}')">{% trans "Delete" %}</button>
|
<th>{% trans 'Actions' %}</th>
|
||||||
</div>
|
</tr>
|
||||||
<div class="panel-body">
|
</thead>
|
||||||
<div class="form-group form-inline">
|
<tbody>
|
||||||
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "MAC" %} </label>
|
{% for network in networks %}
|
||||||
<input class="form-control" type="text" value="{{ network.mac }}" readonly/>
|
<tr>
|
||||||
<label class="control-label"><em>to</em></label>
|
<td class="col-sm-2"><label>eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</label></td>
|
||||||
<input class="form-control" type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
<td><input class="form-control" type="text" value="{{ network.mac }}" readonly/></td>
|
||||||
</div>
|
<td><input class="form-control" type="text" value="{{ network.nic }}" readonly/></td>
|
||||||
<div class="form-group form-inline">
|
<td><input class="form-control" type="text" value="{{ network.filterref }}" readonly/></td>
|
||||||
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "NIC" %} </label>
|
<td class="col-sm-2">
|
||||||
<input class="form-control" type="text" value="{{ network.nic }}" readonly/>
|
<form class="form-horizontal" method="post" name="set_qos{{ forloop.counter0 }}" role="form">{% csrf_token %}
|
||||||
<label class="control-label"><em>to</em></label>
|
<button data-target="#editInstanceNetwork{{ forloop.counter0 }}" type="button" class="btn btn-sm btn-primary"
|
||||||
<select class="form-control" name="net-source-{{ forloop.counter0 }}">
|
title="Edit NIC" data-toggle="modal">
|
||||||
{% for c_net in networks_host %}
|
<span class="glyphicon glyphicon-edit" aria-hidden="true"></span>
|
||||||
<option value="net:{{ c_net }}" {% ifequal c_net network.nic %} selected {% endifequal %}>{% trans 'Network' %} {{ c_net }}</option>
|
</button>
|
||||||
{% endfor %}
|
|
||||||
{% for c_iface in interfaces_host %}
|
<div class="modal fade" id="editInstanceNetwork{{ forloop.counter0 }}" role="dialog" aria-labelledby="editInstanceNetworkLabel" aria-hidden="true">
|
||||||
<option value="iface:{{ c_iface }}" {% ifequal c_iface network.nic %} selected {% endifequal %}>{% trans 'Interface' %} {{ c_iface }}</option>
|
<div class="modal-dialog">
|
||||||
{% endfor %}
|
<div class="modal-content">
|
||||||
</select>
|
<div class="modal-header">
|
||||||
</div>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
<div class="form-group form-inline">
|
<h4 class="modal-title">{% trans "Edit Instance Network" %}</h4>
|
||||||
<label class="col-sm-2 col-sm-offset-1">{% trans "Filter" %} </label>
|
</div>
|
||||||
<input class="form-control" type="text" value="{{ network.filterref }}" readonly/>
|
<div class="modal-body">
|
||||||
<label class="control-label"><em>to</em></label>
|
<div class="form-group form-inline">
|
||||||
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
|
<label class="col-sm-2 control-label">{% trans "MAC" %} </label>
|
||||||
<option value="">{% trans "None" %}</option>
|
<input class="form-control" type="text" value="{{ network.mac }}" readonly/>
|
||||||
{% for c_filters in nwfilters_host %}
|
<label class="control-label"><em>to</em></label>
|
||||||
<option value="{{ c_filters }}" {% ifequal c_filters network.filterref %} selected {% endifequal %}>{{ c_filters }}</option>
|
<input class="form-control" type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||||||
{% endfor %}
|
</div>
|
||||||
</select>
|
<div class="form-group form-inline">
|
||||||
</div>
|
<label class="col-sm-2 control-label">{% trans "NIC" %} </label>
|
||||||
<button class="btn btn-sm btn-primary btn-block" name="change_network" title="{% trans "Apply Network Changes" %}">{% trans "Apply" %}</button>
|
<input class="form-control" type="text" value="{{ network.nic }}" readonly/>
|
||||||
</div>
|
<label class="control-label"><em>to</em></label>
|
||||||
</div>
|
<select class="form-control" name="net-source-{{ forloop.counter0 }}">
|
||||||
{% endfor %}
|
{% for c_net in networks_host %}
|
||||||
</form>
|
<option value="net:{{ c_net }}" {% ifequal c_net network.nic %} selected {% endifequal %}>{% trans 'Network' %} {{ c_net }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
{% for c_iface in interfaces_host %}
|
||||||
|
<option value="iface:{{ c_iface }}" {% ifequal c_iface network.nic %} selected {% endifequal %}>{% trans 'Interface' %} {{ c_iface }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="form-group form-inline">
|
||||||
|
<label class="col-sm-2 control-label">{% trans "Filter" %} </label>
|
||||||
|
<input class="form-control" type="text" value="{{ network.filterref }}" readonly/>
|
||||||
|
<label class="control-label"><em>to</em></label>
|
||||||
|
<select class="form-control" name="net-nwfilter-{{ forloop.counter0 }}">
|
||||||
|
<option value="">{% trans "None" %}</option>
|
||||||
|
{% for c_filters in nwfilters_host %}
|
||||||
|
<option value="{{ c_filters }}" {% ifequal c_filters network.filterref %} selected {% endifequal %}>{{ c_filters }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button class="btn btn-sm btn-primary btn-block" name="change_network" title="{% trans "Apply Network Changes" %}">{% trans "Apply" %}</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button class="btn btn-sm btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete Device" %}"
|
||||||
|
onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i>
|
||||||
|
</button>
|
||||||
|
|
||||||
|
{% include 'add_network_qos.html' with id=forloop.counter0 %}
|
||||||
|
</form>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{% if qos %}
|
||||||
|
<div class="col-xs-10 col-sm-10">
|
||||||
|
<p><strong>{% trans "Qos Configuration" %}</strong></p>
|
||||||
|
</div>
|
||||||
|
<div class="col-xs-12 col-sm-12">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>{% trans "Direction" %}</th>
|
||||||
|
<th>{% trans "Average" %}</th>
|
||||||
|
<th>{% trans "Peak" %}</th>
|
||||||
|
<th>{% trans "Burst" %}</th>
|
||||||
|
<th>{% trans "Actions" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for q, attrs in qos.items %}
|
||||||
|
{% for att in attrs %}
|
||||||
|
<form method="post" role="form">{% csrf_token %}
|
||||||
|
<tr>
|
||||||
|
<td><label class="control-label">{{ q }} {{ att.direction | capfirst }}</label></td>
|
||||||
|
<td><input id="qos_average" class="form-control" name="qos_average"
|
||||||
|
value="{{ att.average|default:'' }}"/></td>
|
||||||
|
<td><input id="qos_peak" class="form-control" name="qos_peak"
|
||||||
|
value="{{ att.peak|default:'' }}"/></td>
|
||||||
|
<td><input id="qos_burst" class="form-control" name="qos_burst"
|
||||||
|
value="{{ att.burst|default:'' }}"/></td>
|
||||||
|
<td class="col-sm-2">
|
||||||
|
<input name="qos_direction" value="{{ att.direction }}" hidden/>
|
||||||
|
<input name="net-mac" value="{{ q }}" hidden/>
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary"
|
||||||
|
name="set_qos" data-toggle="modal"
|
||||||
|
title="Edit Qos" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-save"></i>
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-sm btn-danger"
|
||||||
|
name="unset_qos"
|
||||||
|
title="Delete Qos" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</form>
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="migrate">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="migrate">
|
||||||
|
@ -1209,6 +1290,8 @@
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="options">
|
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="options">
|
||||||
|
<div class="well">
|
||||||
|
<p>{% trans "To set instance template name description, shutdown the instance." %}</p>
|
||||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-3 control-label">{% trans "Title" %}</label>
|
<label class="col-sm-3 control-label">{% trans "Title" %}</label>
|
||||||
|
@ -1225,17 +1308,52 @@
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-3 control-label">{% trans "Is template" %}</label>
|
<label class="col-sm-3 control-label">{% trans "Is template" %}</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input type="checkbox" name="is_template" value="True" id="is_template" {% if instance.is_template %}checked{% endif %} {% if not request.user.is_superuser %}disabled{% endif %}>
|
<input type="checkbox"
|
||||||
|
name="is_template"
|
||||||
|
value="True"
|
||||||
|
id="is_template"
|
||||||
|
{% if instance.is_template %}checked{% endif %}
|
||||||
|
{% if not request.user.is_superuser and not request.user.is_staff %}disabled{% endif %}>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="form-group ">
|
||||||
|
<div class="col-sm-offset-3 col-sm-6">
|
||||||
|
{% ifequal status 5 %}
|
||||||
|
<button type="submit" class="btn btn-block btn-success" name="change_options">{% trans "Change" %}</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-block btn-success disabled" name="change_options">{% trans "Change" %}</button>
|
||||||
|
{% endifequal %}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class="well">
|
||||||
|
<p>{% trans "To set instance video model, shutdown the instance." %}</p>
|
||||||
|
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="video_model_select" class="col-sm-3 control-label">{% trans "Primary Video Model" %}</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<div class="input-group">
|
||||||
|
<select id="video_model_select" class="form-control" name="video_model">
|
||||||
|
<option value="" style="font-weight: bold">{% trans "please choose" %}</option>
|
||||||
|
{% for vmodel in videos_host %}
|
||||||
|
<option value="{{ vmodel }}">{{ vmodel }}</option>
|
||||||
|
{% endfor %}
|
||||||
|
</select>
|
||||||
|
<span class="input-group-btn">
|
||||||
|
{% ifequal status 5 %}
|
||||||
|
<button type="submit" class="btn btn-success" name="set_video_model">{% trans "Set" %}</button>
|
||||||
|
{% else %}
|
||||||
|
<button class="btn btn-success disabled" name="set_video_model">{% trans "Set" %}</button>
|
||||||
|
{% endifequal %}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{% ifequal status 5 %}
|
|
||||||
<button type="submit" class="btn btn-lg btn-success pull-right" name="change_options">{% trans "Change" %}</button>
|
|
||||||
{% else %}
|
|
||||||
<button class="btn btn-lg btn-success pull-right disabled" name="change_options">{% trans "Change" %}</button>
|
|
||||||
{% endifequal %}
|
|
||||||
</form>
|
</form>
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -1516,6 +1634,13 @@
|
||||||
$("#console_select_listen_address option[value='" + console_listen_address + "']").prop('selected', true);
|
$("#console_select_listen_address option[value='" + console_listen_address + "']").prop('selected', true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
$(document).ready(function () {
|
||||||
|
// get video model or fall back to default
|
||||||
|
let video_model = "{{ video_model }}"
|
||||||
|
if (video_model != '') {
|
||||||
|
$("#video_model_select option[value='" + video_model + "']").prop('selected', true);
|
||||||
|
}
|
||||||
|
});
|
||||||
$(document).ready(function () {
|
$(document).ready(function () {
|
||||||
// set vdi url
|
// set vdi url
|
||||||
$.get("{% url 'vdi_url' vname %}", function(data) {
|
$.get("{% url 'vdi_url' vname %}", function(data) {
|
||||||
|
|
|
@ -272,6 +272,7 @@ def instance(request, compute_id, vname):
|
||||||
title = conn.get_title()
|
title = conn.get_title()
|
||||||
description = conn.get_description()
|
description = conn.get_description()
|
||||||
networks = conn.get_net_device()
|
networks = conn.get_net_device()
|
||||||
|
qos = conn.get_all_qos()
|
||||||
disks = conn.get_disk_devices()
|
disks = conn.get_disk_devices()
|
||||||
media = conn.get_media_devices()
|
media = conn.get_media_devices()
|
||||||
if len(media) != 0:
|
if len(media) != 0:
|
||||||
|
@ -290,6 +291,7 @@ def instance(request, compute_id, vname):
|
||||||
console_port = conn.get_console_port()
|
console_port = conn.get_console_port()
|
||||||
console_keymap = conn.get_console_keymap()
|
console_keymap = conn.get_console_keymap()
|
||||||
console_listen_address = conn.get_console_listen_addr()
|
console_listen_address = conn.get_console_listen_addr()
|
||||||
|
video_model = conn.get_video_model()
|
||||||
snapshots = sorted(conn.get_snapshot(), reverse=True, key=lambda k: k['date'])
|
snapshots = sorted(conn.get_snapshot(), reverse=True, key=lambda k: k['date'])
|
||||||
inst_xml = conn._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
inst_xml = conn._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
has_managed_save_image = conn.get_managed_save_image()
|
has_managed_save_image = conn.get_managed_save_image()
|
||||||
|
@ -327,6 +329,7 @@ def instance(request, compute_id, vname):
|
||||||
vcpu_host = len(vcpu_range)
|
vcpu_host = len(vcpu_range)
|
||||||
memory_host = conn.get_max_memory()
|
memory_host = conn.get_max_memory()
|
||||||
bus_host = conn.get_disk_bus_types()
|
bus_host = conn.get_disk_bus_types()
|
||||||
|
videos_host = conn.get_video_models()
|
||||||
networks_host = sorted(conn.get_networks())
|
networks_host = sorted(conn.get_networks())
|
||||||
interfaces_host = sorted(conn.get_ifaces())
|
interfaces_host = sorted(conn.get_ifaces())
|
||||||
nwfilters_host = conn.get_nwfilters()
|
nwfilters_host = conn.get_nwfilters()
|
||||||
|
@ -480,10 +483,11 @@ def instance(request, compute_id, vname):
|
||||||
conn.resize_cpu(cur_vcpu, vcpu)
|
conn.resize_cpu(cur_vcpu, vcpu)
|
||||||
msg = _("Resize CPU")
|
msg = _("Resize CPU")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
||||||
|
|
||||||
if 'resizevm_mem' in request.POST and (
|
if 'resizevm_mem' in request.POST and (request.user.is_superuser or
|
||||||
request.user.is_superuser or request.user.is_staff or userinstance.is_change):
|
request.user.is_staff or
|
||||||
|
userinstance.is_change):
|
||||||
new_memory = request.POST.get('memory', '')
|
new_memory = request.POST.get('memory', '')
|
||||||
new_memory_custom = request.POST.get('memory_custom', '')
|
new_memory_custom = request.POST.get('memory_custom', '')
|
||||||
if new_memory_custom:
|
if new_memory_custom:
|
||||||
|
@ -502,7 +506,7 @@ def instance(request, compute_id, vname):
|
||||||
conn.resize_mem(cur_memory, memory)
|
conn.resize_mem(cur_memory, memory)
|
||||||
msg = _("Resize Memory")
|
msg = _("Resize Memory")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
||||||
|
|
||||||
if 'resizevm_disk' in request.POST and (
|
if 'resizevm_disk' in request.POST and (
|
||||||
request.user.is_superuser or request.user.is_staff or userinstance.is_change):
|
request.user.is_superuser or request.user.is_staff or userinstance.is_change):
|
||||||
|
@ -522,7 +526,7 @@ def instance(request, compute_id, vname):
|
||||||
conn.resize_disk(disks_new)
|
conn.resize_disk(disks_new)
|
||||||
msg = _("Resize")
|
msg = _("Resize")
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
return HttpResponseRedirect(request.get_full_path() + '#resize')
|
||||||
|
|
||||||
if 'add_new_vol' in request.POST and allow_admin_or_not_template:
|
if 'add_new_vol' in request.POST and allow_admin_or_not_template:
|
||||||
conn_create = wvmCreate(compute.hostname,
|
conn_create = wvmCreate(compute.hostname,
|
||||||
|
@ -699,7 +703,8 @@ def instance(request, compute_id, vname):
|
||||||
msg = _("Set boot order")
|
msg = _("Set boot order")
|
||||||
|
|
||||||
if not conn.get_status() == 5:
|
if not conn.get_status() == 5:
|
||||||
messages.success(request, _("Boot menu changes applied. But it will be activated after shutdown"))
|
messages.success(request, _("Boot menu changes applied. " +
|
||||||
|
"But it will be activated after shutdown"))
|
||||||
else:
|
else:
|
||||||
messages.success(request, _("Boot order changed successfully."))
|
messages.success(request, _("Boot order changed successfully."))
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
@ -727,7 +732,8 @@ def instance(request, compute_id, vname):
|
||||||
error_messages.append(msg)
|
error_messages.append(msg)
|
||||||
if not error_messages:
|
if not error_messages:
|
||||||
if not conn.set_console_passwd(passwd):
|
if not conn.set_console_passwd(passwd):
|
||||||
msg = _("Error setting console password. You should check that your instance have an graphic device.")
|
msg = _("Error setting console password. " +
|
||||||
|
"You should check that your instance have an graphic device.")
|
||||||
error_messages.append(msg)
|
error_messages.append(msg)
|
||||||
else:
|
else:
|
||||||
msg = _("Set VNC password")
|
msg = _("Set VNC password")
|
||||||
|
@ -760,6 +766,13 @@ def instance(request, compute_id, vname):
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#vncsettings')
|
return HttpResponseRedirect(request.get_full_path() + '#vncsettings')
|
||||||
|
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
|
if 'set_video_model' in request.POST:
|
||||||
|
video_model = request.POST.get('video_model', 'vga')
|
||||||
|
conn.set_video_model(video_model)
|
||||||
|
msg = _("Set Video Model")
|
||||||
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#options')
|
||||||
|
|
||||||
if 'migrate' in request.POST:
|
if 'migrate' in request.POST:
|
||||||
compute_id = request.POST.get('compute_id', '')
|
compute_id = request.POST.get('compute_id', '')
|
||||||
live = request.POST.get('live_migrate', False)
|
live = request.POST.get('live_migrate', False)
|
||||||
|
@ -808,6 +821,40 @@ def instance(request, compute_id, vname):
|
||||||
addlogmsg(request.user.username, instance.name, msg)
|
addlogmsg(request.user.username, instance.name, msg)
|
||||||
return HttpResponseRedirect(request.get_full_path() + '#network')
|
return HttpResponseRedirect(request.get_full_path() + '#network')
|
||||||
|
|
||||||
|
if 'set_qos' in request.POST:
|
||||||
|
qos_dir = request.POST.get('qos_direction', '')
|
||||||
|
average = request.POST.get('qos_average') or 0
|
||||||
|
peak = request.POST.get('qos_peak') or 0
|
||||||
|
burst = request.POST.get('qos_burst') or 0
|
||||||
|
keys = request.POST.keys()
|
||||||
|
mac_key = [key for key in keys if 'mac' in key]
|
||||||
|
if mac_key: mac = request.POST.get(mac_key[0])
|
||||||
|
|
||||||
|
try:
|
||||||
|
conn.set_qos(mac, qos_dir, average, peak, burst)
|
||||||
|
if conn.get_status() == 5:
|
||||||
|
messages.success(request, "{} Qos is set".format(qos_dir.capitalize()))
|
||||||
|
else:
|
||||||
|
messages.success(request,
|
||||||
|
"{} Qos is set. Network XML is changed.".format(qos_dir.capitalize()) +
|
||||||
|
"Stop and start network to activate new config")
|
||||||
|
|
||||||
|
except libvirtError as le:
|
||||||
|
messages.error(request, le.message)
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#network')
|
||||||
|
if 'unset_qos' in request.POST:
|
||||||
|
qos_dir = request.POST.get('qos_direction', '')
|
||||||
|
mac = request.POST.get('net-mac')
|
||||||
|
conn.unset_qos(mac, qos_dir)
|
||||||
|
|
||||||
|
if conn.get_status() == 5:
|
||||||
|
messages.success(request, "{} Qos is deleted".format(qos_dir.capitalize()))
|
||||||
|
else:
|
||||||
|
messages.success(request,
|
||||||
|
"{} Qos is deleted. Network XML is changed. ".format(qos_dir.capitalize()) +
|
||||||
|
"Stop and start network to activate new config.")
|
||||||
|
return HttpResponseRedirect(request.get_full_path() + '#network')
|
||||||
|
|
||||||
if 'add_owner' in request.POST:
|
if 'add_owner' in request.POST:
|
||||||
user_id = int(request.POST.get('user_id', ''))
|
user_id = int(request.POST.get('user_id', ''))
|
||||||
|
|
||||||
|
@ -1014,7 +1061,7 @@ def get_host_instances(request, comp):
|
||||||
|
|
||||||
conn.close()
|
conn.close()
|
||||||
else:
|
else:
|
||||||
raise libvirtError("Problem occured with {} - {}".format(comp.name, status))
|
raise libvirtError("Problem occurred with {} - {}".format(comp.name, status))
|
||||||
return all_host_vms
|
return all_host_vms
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
{% load i18n %}
|
{% load i18n %}
|
||||||
{% if request.user.is_superuser %}
|
{% if request.user.is_superuser %}
|
||||||
<a href="#AddInboundQos" type="button" class="btn btn-success pull-right" data-toggle="modal" title="add inbound qos">
|
<a href="#AddQos{{ id }}" type="button" class="btn btn-sm btn-success pull-right" data-toggle="modal" title="add qos">
|
||||||
<span class="glyphicon glyphicon-arrow-down" aria-hidden="true"></span>
|
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<!-- Modal pool -->
|
<!-- Modal pool -->
|
||||||
<div class="modal fade" id="AddInboundQos" tabindex="-1" role="dialog" aria-labelledby="AddInboundQosLabel"
|
<div class="modal fade" id="AddQos{{ id }}" tabindex="-1" role="dialog" aria-labelledby="AddQosLabel"
|
||||||
aria-hidden="true">
|
aria-hidden="true">
|
||||||
<div class="modal-dialog">
|
<div class="modal-dialog">
|
||||||
<div class="modal-content">
|
<div class="modal-content">
|
||||||
|
@ -13,36 +13,43 @@
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
||||||
<h4 class="modal-title">{% trans "Add Inbound Qos for Network" %}</h4>
|
<h4 class="modal-title">{% trans "Add Inbound Qos for Network" %}</h4>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-body">
|
<div class="modal-body">
|
||||||
<form class="form-horizontal" method="post" name="set_qos" role="form">{% csrf_token %}
|
<div class="form-group">
|
||||||
|
<label class="col-sm-4 control-label">{% trans "Direction" %}:</label>
|
||||||
|
<div class="col-sm-6">
|
||||||
|
<select class="form-control" name="qos_direction">
|
||||||
|
<option value="inbound">{% trans 'Inbound' %}</option>
|
||||||
|
<option value="outbound">{% trans 'Outbound' %}</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-4 control-label">{% trans "Average" %}:</label>
|
<label class="col-sm-4 control-label">{% trans "Average" %}:</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input class="form-control" name="qos_inbound_average" required pattern="[0-9]+"/>
|
<input class="form-control" name="qos_average" placeholder="kilobytes"
|
||||||
|
required pattern="[0-9]+"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-4 control-label">{% trans "Peak" %}:</label>
|
<label class="col-sm-4 control-label">{% trans "Peak" %}:</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input class="form-control" name="qos_inbound_peak"
|
<input class="form-control" name="qos_peak" placeholder="kilobytes"
|
||||||
required pattern="[0-9]+"/>
|
pattern="[0-9]+"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-sm-4 control-label">{% trans "Burst" %}:</label>
|
<label class="col-sm-4 control-label">{% trans "Burst" %}:</label>
|
||||||
<div class="col-sm-6">
|
<div class="col-sm-6">
|
||||||
<input class="form-control" name="qos_inbound_burst" required pattern="[0-9]+"/>
|
<input class="form-control" name="qos_burst" placeholder="kilobytes"
|
||||||
|
pattern="[0-9]+"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<input name="qos_direction" value="inbound" hidden/>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="modal-footer">
|
<div class="modal-footer">
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans 'Close' %}</button>
|
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans 'Close' %}</button>
|
||||||
<button type="submit" class="btn btn-primary" name="set_qos">{% trans 'Save' %}</button>
|
<button type="submit" class="btn btn-primary" name="set_qos">{% trans 'Save' %}</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
</div> <!-- /.modal-dialog -->
|
</div> <!-- /.modal-dialog -->
|
||||||
</div> <!-- /.modal -->
|
</div> <!-- /.modal -->
|
|
@ -1,49 +0,0 @@
|
||||||
{% load i18n %}
|
|
||||||
{% if request.user.is_superuser %}
|
|
||||||
<a href="#AddOutboundQos" type="button" class="btn btn-success pull-right" data-toggle="modal" title="add outbound qos">
|
|
||||||
<span class="glyphicon glyphicon-arrow-up" aria-hidden="true"></span>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
<!-- Modal pool -->
|
|
||||||
<div class="modal fade" id="AddOutboundQos" tabindex="-1" role="dialog" aria-labelledby="AddOutboundQosLabel"
|
|
||||||
aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<button type="button" class="close" data-dismiss="modal" aria-hidden="true">×</button>
|
|
||||||
<h4 class="modal-title">{% trans "Add Outbound Qos for Network" %}</h4>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-body">
|
|
||||||
<form class="form-horizontal" method="post" name="set_qos" role="form">{% csrf_token %}
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-4 control-label">{% trans "Average" %}:</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input class="form-control" name="qos_outbound_average" required pattern="[0-9]+"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-4 control-label">{% trans "Peak" %}:</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input class="form-control" name="qos_outbound_peak"
|
|
||||||
required pattern="[0-9]+"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="form-group">
|
|
||||||
<label class="col-sm-4 control-label">{% trans "Burst" %}:</label>
|
|
||||||
<div class="col-sm-6">
|
|
||||||
<input class="form-control" name="qos_outbound_burst" required pattern="[0-9]+"/>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<input name="qos_direction" value="outbound" hidden/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans 'Close' %}</button>
|
|
||||||
<button type="submit" class="btn btn-primary" name="set_qos">{% trans 'Save' %}</button>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div> <!-- /.modal-dialog -->
|
|
||||||
</div> <!-- /.modal -->
|
|
||||||
{% endif %}
|
|
|
@ -339,59 +339,61 @@
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% ifequal state 0 %}
|
{% if net_forward.0 == 'route' or net_forward.0 == 'nat' or net_forward.0 == 'isolated' %}
|
||||||
{% include 'add_outbound_qos.html' %}
|
{% if state == 0 and qos.items|length != 2%}
|
||||||
{% include 'add_inbound_qos.html' %}
|
<form class="form-horizontal" method="post" name="set_qos" role="form">{% csrf_token %}
|
||||||
{% endifequal %}
|
{% include 'add_network_qos.html' %}
|
||||||
|
</form>
|
||||||
|
{% endif %}
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<h3 class="page-header">{% trans "Qos Configuration" %}
|
<h3 class="page-header">{% trans "Qos Configuration" %}</h3>
|
||||||
</h3>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="row">
|
|
||||||
<div class="col-sm-12">
|
|
||||||
<table class="table table-hover">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th style="text-align: center">{% trans "Direction" %}</th>
|
|
||||||
<th style="text-align: center">{% trans "Average" %}</th>
|
|
||||||
<th style="text-align: center">{% trans "Peak" %}</th>
|
|
||||||
<th style="text-align: center">{% trans "Burst" %}</th>
|
|
||||||
<th style="text-align: center">{% trans "Actions" %}</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% for q, att in qos.items %}
|
|
||||||
<form method="post" role="form">{% csrf_token %}
|
|
||||||
<tr>
|
|
||||||
<td><label class="control-label">{{ q | capfirst }}</label></td>
|
|
||||||
<td><input id="qos_{{ q }}_av" class="form-control" name="qos_{{ q }}_average"
|
|
||||||
value="{{ att.average }}"/></td>
|
|
||||||
<td><input id="qos_{{ q }}_peak" class="form-control" name="qos_{{ q }}_peak"
|
|
||||||
value="{{ att.peak }}"/></td>
|
|
||||||
<td><input id="qos_{{ q }}_burst" class="form-control" name="qos_{{ q }}_burst"
|
|
||||||
value="{{ att.burst }}"/></td>
|
|
||||||
<td>
|
|
||||||
<input name="qos_direction" value="{{ q }}" hidden/>
|
|
||||||
<button type="submit" class="btn btn-sm btn-primary"
|
|
||||||
name="set_qos"
|
|
||||||
title="Edit Qos" onclick="return confirm('{% trans "Are you sure?" %}')">
|
|
||||||
<i class="glyphicon glyphicon-save"></i>
|
|
||||||
</button>
|
|
||||||
<button type="submit" class="btn btn-sm btn-danger"
|
|
||||||
name="unset_qos"
|
|
||||||
title="Delete Qos" onclick="return confirm('{% trans "Are you sure?" %}')">
|
|
||||||
<i class="glyphicon glyphicon-trash"></i>
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
</form>
|
|
||||||
{% endfor %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-sm-12">
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th style="text-align: center">{% trans "Direction" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Average" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Peak" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Burst" %}</th>
|
||||||
|
<th style="text-align: center">{% trans "Actions" %}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for q, att in qos.items %}
|
||||||
|
<form method="post" role="form">{% csrf_token %}
|
||||||
|
<tr>
|
||||||
|
<td><label class="control-label">{{ q | capfirst }}</label></td>
|
||||||
|
<td><input id="qos_average" class="form-control" name="qos_average"
|
||||||
|
value="{{ att.average|default:'' }}"/></td>
|
||||||
|
<td><input id="qos_peak" class="form-control" name="qos_peak"
|
||||||
|
value="{{ att.peak|default:'' }}"/></td>
|
||||||
|
<td><input id="qos_burst" class="form-control" name="qos_burst"
|
||||||
|
value="{{ att.burst|default:'' }}"/></td>
|
||||||
|
<td>
|
||||||
|
<input name="qos_direction" value="{{ q }}" hidden/>
|
||||||
|
<button type="submit" class="btn btn-sm btn-primary"
|
||||||
|
name="set_qos" data-toggle="modal"
|
||||||
|
title="Edit Qos" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-save"></i>
|
||||||
|
</button>
|
||||||
|
<button type="submit" class="btn btn-sm btn-danger"
|
||||||
|
name="unset_qos"
|
||||||
|
title="Delete Qos" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||||
|
<i class="glyphicon glyphicon-trash"></i>
|
||||||
|
</button>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</form>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{% endif %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
{% block script %}
|
{% block script %}
|
||||||
<script>
|
<script>
|
||||||
|
|
|
@ -195,19 +195,21 @@ def network(request, compute_id, pool):
|
||||||
else:
|
else:
|
||||||
messages.success(request, _("Network XML is changed."))
|
messages.success(request, _("Network XML is changed."))
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
|
|
||||||
if 'set_qos' in request.POST:
|
if 'set_qos' in request.POST:
|
||||||
qos_dir = request.POST.get('qos_direction', '')
|
qos_dir = request.POST.get('qos_direction', '')
|
||||||
average = request.POST.get('qos_{}_average'.format(qos_dir), '')
|
average = request.POST.get('qos_average') or 0
|
||||||
peak = request.POST.get('qos_{}_peak'.format(qos_dir), '')
|
peak = request.POST.get('qos_peak') or 0
|
||||||
burst = request.POST.get('qos_{}_burst'.format(qos_dir), '')
|
burst = request.POST.get('qos_burst') or 0
|
||||||
|
|
||||||
conn.set_qos(qos_dir, average, peak, burst)
|
try:
|
||||||
if conn.is_active():
|
conn.set_qos(qos_dir, average, peak, burst)
|
||||||
messages.success(request, "{} Qos is set. Network XML is changed.".format(qos_dir.capitalize()) +
|
if conn.is_active():
|
||||||
"Stop and start network to activate new config")
|
messages.success(request, "{} Qos is set. Network XML is changed.".format(qos_dir.capitalize()) +
|
||||||
else:
|
"Stop and start network to activate new config")
|
||||||
messages.success(request, "{} Qos is set".format(qos_dir.capitalize()))
|
else:
|
||||||
|
messages.success(request, "{} Qos is set".format(qos_dir.capitalize()))
|
||||||
|
except libvirtError as le:
|
||||||
|
messages.error(request, le.message)
|
||||||
return HttpResponseRedirect(request.get_full_path())
|
return HttpResponseRedirect(request.get_full_path())
|
||||||
if 'unset_qos' in request.POST:
|
if 'unset_qos' in request.POST:
|
||||||
qos_dir = request.POST.get('qos_direction', '')
|
qos_dir = request.POST.get('qos_direction', '')
|
||||||
|
|
|
@ -21,9 +21,9 @@ html {
|
||||||
}
|
}
|
||||||
|
|
||||||
#noVNC_status_bar {
|
#noVNC_status_bar {
|
||||||
|
margin-top: 52px;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display:flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#noVNC_status {
|
#noVNC_status {
|
||||||
|
|
|
@ -81,7 +81,7 @@ body
|
||||||
{
|
{
|
||||||
min-height: 600px;
|
min-height: 600px;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
margin: 10px;
|
margin: 62px 10px 10px 10px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
background-color: #333333;
|
background-color: #333333;
|
||||||
}
|
}
|
||||||
|
|
|
@ -480,7 +480,7 @@ class wvmConnect(object):
|
||||||
"""Get available image filename extensions"""
|
"""Get available image filename extensions"""
|
||||||
return ['img', 'qcow', 'qcow2']
|
return ['img', 'qcow', 'qcow2']
|
||||||
|
|
||||||
def get_video(self):
|
def get_video_models(self):
|
||||||
""" Get available graphics video types """
|
""" Get available graphics video types """
|
||||||
def get_video_list(ctx):
|
def get_video_list(ctx):
|
||||||
result = []
|
result = []
|
||||||
|
@ -508,6 +508,15 @@ class wvmConnect(object):
|
||||||
def get_network(self, net):
|
def get_network(self, net):
|
||||||
return self.wvm.networkLookupByName(net)
|
return self.wvm.networkLookupByName(net)
|
||||||
|
|
||||||
|
def get_network_forward(self, net_name):
|
||||||
|
def get_forward(doc):
|
||||||
|
forward_mode = util.get_xpath(doc, '/network/forward/@mode')
|
||||||
|
return forward_mode or 'isolated'
|
||||||
|
|
||||||
|
net = self.get_network(net_name)
|
||||||
|
xml = net.XMLDesc(0)
|
||||||
|
return util.get_xml_path(xml, func=get_forward)
|
||||||
|
|
||||||
def get_nwfilter(self, name):
|
def get_nwfilter(self, name):
|
||||||
return self.wvm.nwfilterLookupByName(name)
|
return self.wvm.nwfilterLookupByName(name)
|
||||||
|
|
||||||
|
|
|
@ -7,6 +7,7 @@ except:
|
||||||
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
|
from libvirt import libvirtError, VIR_DOMAIN_XML_SECURE, VIR_MIGRATE_LIVE
|
||||||
from vrtManager import util
|
from vrtManager import util
|
||||||
from xml.etree import ElementTree
|
from xml.etree import ElementTree
|
||||||
|
from lxml import etree
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from vrtManager.connection import wvmConnect
|
from vrtManager.connection import wvmConnect
|
||||||
from vrtManager.storage import wvmStorage
|
from vrtManager.storage import wvmStorage
|
||||||
|
@ -157,6 +158,12 @@ class wvmInstance(wvmConnect):
|
||||||
return self.wvm.defineXML(xml)
|
return self.wvm.defineXML(xml)
|
||||||
|
|
||||||
def get_status(self):
|
def get_status(self):
|
||||||
|
"""
|
||||||
|
VIR_DOMAIN_NOSTATE = 0
|
||||||
|
VIR_DOMAIN_RUNNING = 1
|
||||||
|
VIR_DOMAIN_PAUSED = 3
|
||||||
|
VIR_DOMAIN_SHUTOFF = 5
|
||||||
|
"""
|
||||||
return self.instance.info()[0]
|
return self.instance.info()[0]
|
||||||
|
|
||||||
def get_autostart(self):
|
def get_autostart(self):
|
||||||
|
@ -229,17 +236,38 @@ class wvmInstance(wvmConnect):
|
||||||
|
|
||||||
def networks(ctx):
|
def networks(ctx):
|
||||||
result = []
|
result = []
|
||||||
|
inbound = outbound = []
|
||||||
for net in ctx.xpath('/domain/devices/interface'):
|
for net in ctx.xpath('/domain/devices/interface'):
|
||||||
mac_host = net.xpath('mac/@address')[0]
|
mac_inst = net.xpath('mac/@address')[0]
|
||||||
network_host = net.xpath('source/@network|source/@bridge|source/@dev')[0]
|
nic_inst = net.xpath('source/@network|source/@bridge|source/@dev')[0]
|
||||||
target_host = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0]
|
target_inst = '' if not net.xpath('target/@dev') else net.xpath('target/@dev')[0]
|
||||||
filterref_host = '' if not net.xpath('filterref/@filter') else net.xpath('filterref/@filter')[0]
|
filterref_inst = '' if not net.xpath('filterref/@filter') else net.xpath('filterref/@filter')[0]
|
||||||
|
if net.xpath('bandwidth/inbound'):
|
||||||
|
in_attr = net.xpath('bandwidth/inbound')[0]
|
||||||
|
in_av = in_attr.get('average')
|
||||||
|
in_peak = in_attr.get('peak')
|
||||||
|
in_burst = in_attr.get('burst')
|
||||||
|
inbound = {'average': in_av, 'peak': in_peak, 'burst': in_burst}
|
||||||
|
if net.xpath('bandwidth/outbound'):
|
||||||
|
out_attr = net.xpath('bandwidth/outbound')[0]
|
||||||
|
out_av = out_attr.get('average')
|
||||||
|
out_peak = out_attr.get('peak')
|
||||||
|
out_burst = out_attr.get('burst')
|
||||||
|
outbound = {'average': out_av, 'peak': out_peak, 'burst': out_burst}
|
||||||
|
|
||||||
try:
|
try:
|
||||||
net = self.get_network(network_host)
|
net = self.get_network(nic_inst)
|
||||||
ip = get_mac_ipaddr(net, mac_host)
|
ip = get_mac_ipaddr(net, mac_inst)
|
||||||
except libvirtError:
|
except libvirtError:
|
||||||
ip = None
|
ip = None
|
||||||
result.append({'mac': mac_host, 'nic': network_host, 'target': target_host, 'ip': ip, 'filterref': filterref_host})
|
result.append({'mac': mac_inst,
|
||||||
|
'nic': nic_inst,
|
||||||
|
'target': target_inst,
|
||||||
|
'ip': ip,
|
||||||
|
'filterref': filterref_inst,
|
||||||
|
'inbound': inbound,
|
||||||
|
'outbound': outbound,
|
||||||
|
})
|
||||||
return result
|
return result
|
||||||
|
|
||||||
return util.get_xml_path(self._XMLDesc(0), func=networks)
|
return util.get_xml_path(self._XMLDesc(0), func=networks)
|
||||||
|
@ -680,8 +708,7 @@ class wvmInstance(wvmConnect):
|
||||||
def get_console_port(self, console_type=None):
|
def get_console_port(self, console_type=None):
|
||||||
if console_type is None:
|
if console_type is None:
|
||||||
console_type = self.get_console_type()
|
console_type = self.get_console_type()
|
||||||
port = util.get_xml_path(self._XMLDesc(0),
|
port = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics[@type='%s']/@port" % console_type)
|
||||||
"/domain/devices/graphics[@type='%s']/@port" % console_type)
|
|
||||||
return port
|
return port
|
||||||
|
|
||||||
def get_console_websocket_port(self):
|
def get_console_websocket_port(self):
|
||||||
|
@ -691,8 +718,7 @@ class wvmInstance(wvmConnect):
|
||||||
return websocket_port
|
return websocket_port
|
||||||
|
|
||||||
def get_console_passwd(self):
|
def get_console_passwd(self):
|
||||||
return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE),
|
return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@passwd")
|
||||||
"/domain/devices/graphics/@passwd")
|
|
||||||
|
|
||||||
def set_console_passwd(self, passwd):
|
def set_console_passwd(self, passwd):
|
||||||
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
|
@ -735,8 +761,29 @@ class wvmInstance(wvmConnect):
|
||||||
self._defineXML(newxml)
|
self._defineXML(newxml)
|
||||||
|
|
||||||
def get_console_keymap(self):
|
def get_console_keymap(self):
|
||||||
return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE),
|
return util.get_xml_path(self._XMLDesc(VIR_DOMAIN_XML_SECURE), "/domain/devices/graphics/@keymap") or ''
|
||||||
"/domain/devices/graphics/@keymap") or ''
|
|
||||||
|
def get_video_model(self):
|
||||||
|
""" :return only primary video card"""
|
||||||
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
|
tree = etree.fromstring(xml)
|
||||||
|
video_models = tree.xpath("/domain/devices/video/model")
|
||||||
|
for model in video_models:
|
||||||
|
if model.get('primary') == 'yes' or len(video_models) == 1:
|
||||||
|
return model.get('type')
|
||||||
|
|
||||||
|
def set_video_model(self, model):
|
||||||
|
""" Changes only primary video card"""
|
||||||
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
|
tree = etree.fromstring(xml)
|
||||||
|
video_models = tree.xpath("/domain/devices/video/model")
|
||||||
|
video_xml = "<model type='{}'/>".format(model)
|
||||||
|
for model in video_models:
|
||||||
|
if model.get('primary') == 'yes' or len(video_models) == 1:
|
||||||
|
parent = model.getparent()
|
||||||
|
parent.remove(model)
|
||||||
|
parent.append(etree.fromstring(video_xml))
|
||||||
|
self._defineXML(etree.tostring(tree))
|
||||||
|
|
||||||
def resize(self, cur_memory, memory, cur_vcpu, vcpu, disks=[]):
|
def resize(self, cur_memory, memory, cur_vcpu, vcpu, disks=[]):
|
||||||
"""
|
"""
|
||||||
|
@ -1007,25 +1054,34 @@ class wvmInstance(wvmConnect):
|
||||||
bridge_name = net.bridgeName()
|
bridge_name = net.bridgeName()
|
||||||
return bridge_name
|
return bridge_name
|
||||||
|
|
||||||
def add_network(self, mac_address, source, source_type='net', interface_type='bridge', model='virtio', nwfilter=None):
|
def add_network(self, mac_address, source, source_type='net', model='virtio', nwfilter=None):
|
||||||
bridge_name = self.get_bridge_name(source, source_type)
|
bridge_name = self.get_bridge_name(source, source_type)
|
||||||
xml_interface = """
|
|
||||||
<interface type='%s'>
|
forward_mode = self.get_network_forward(source)
|
||||||
<mac address='%s'/>
|
if forward_mode in ['nat', 'isolated', 'routed']:
|
||||||
<source bridge='%s'/>
|
interface_type = 'network'
|
||||||
<model type='%s'/>
|
else:
|
||||||
""" % (interface_type, mac_address, bridge_name, model)
|
interface_type = 'bridge'
|
||||||
|
|
||||||
|
xml_iface = """
|
||||||
|
<interface type='%s'>
|
||||||
|
<mac address='%s'/>""" % (interface_type, mac_address)
|
||||||
|
if interface_type == 'network':
|
||||||
|
xml_iface += """<source network='%s'/>""" % source
|
||||||
|
else:
|
||||||
|
xml_iface += """<source bridge='%s'/>""" % bridge_name
|
||||||
|
xml_iface += """<model type='%s'/>""" % model
|
||||||
if nwfilter:
|
if nwfilter:
|
||||||
xml_interface += """
|
xml_iface += """
|
||||||
<filterref filter='%s'/>
|
<filterref filter='%s'/>
|
||||||
""" % nwfilter
|
""" % nwfilter
|
||||||
xml_interface += """</interface>"""
|
xml_iface += """</interface>"""
|
||||||
|
|
||||||
if self.get_status() == 1:
|
if self.get_status() == 1:
|
||||||
self.instance.attachDeviceFlags(xml_interface, VIR_DOMAIN_AFFECT_LIVE)
|
self.instance.attachDeviceFlags(xml_iface, VIR_DOMAIN_AFFECT_LIVE)
|
||||||
self.instance.attachDeviceFlags(xml_interface, VIR_DOMAIN_AFFECT_CONFIG)
|
self.instance.attachDeviceFlags(xml_iface, VIR_DOMAIN_AFFECT_CONFIG)
|
||||||
if self.get_status() == 5:
|
if self.get_status() == 5:
|
||||||
self.instance.attachDeviceFlags(xml_interface, VIR_DOMAIN_AFFECT_CONFIG)
|
self.instance.attachDeviceFlags(xml_iface, VIR_DOMAIN_AFFECT_CONFIG)
|
||||||
|
|
||||||
def delete_network(self, mac_address):
|
def delete_network(self, mac_address):
|
||||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||||
|
@ -1044,10 +1100,11 @@ class wvmInstance(wvmConnect):
|
||||||
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||||
tree = ElementTree.fromstring(xml)
|
tree = ElementTree.fromstring(xml)
|
||||||
for num, interface in enumerate(tree.findall('devices/interface')):
|
for num, interface in enumerate(tree.findall('devices/interface')):
|
||||||
net_source = network_data['net-source-' + str(num)]
|
net_mac = network_data.get('net-mac-' + str(num))
|
||||||
net_source_type = network_data['net-source-' + str(num) + '-type']
|
if net_mac is None: continue
|
||||||
net_mac = network_data['net-mac-' + str(num)]
|
net_source = network_data.get('net-source-' + str(num))
|
||||||
net_filter = network_data['net-nwfilter-' + str(num)]
|
net_source_type = network_data.get('net-source-' + str(num) + '-type')
|
||||||
|
net_filter = network_data.get('net-nwfilter-' + str(num))
|
||||||
bridge_name = self.get_bridge_name(net_source, net_source_type)
|
bridge_name = self.get_bridge_name(net_source, net_source_type)
|
||||||
if interface.get('type') == 'bridge':
|
if interface.get('type') == 'bridge':
|
||||||
source = interface.find('mac')
|
source = interface.find('mac')
|
||||||
|
@ -1103,10 +1160,78 @@ class wvmInstance(wvmConnect):
|
||||||
tree = ElementTree.fromstring(xml)
|
tree = ElementTree.fromstring(xml)
|
||||||
|
|
||||||
self._set_options(tree, options)
|
self._set_options(tree, options)
|
||||||
|
|
||||||
new_xml = ElementTree.tostring(tree)
|
new_xml = ElementTree.tostring(tree)
|
||||||
self._defineXML(new_xml)
|
self._defineXML(new_xml)
|
||||||
|
|
||||||
def set_memory(self, size, flags=0):
|
def set_memory(self, size, flags=0):
|
||||||
self.instance.setMemoryFlags(size, flags)
|
self.instance.setMemoryFlags(size, flags)
|
||||||
|
|
||||||
|
def get_all_qos(self):
|
||||||
|
qos_values = dict()
|
||||||
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
|
qos = tree.xpath("/domain/devices/interface")
|
||||||
|
|
||||||
|
for q in qos:
|
||||||
|
bound_list = list()
|
||||||
|
mac = q.xpath('mac/@address')
|
||||||
|
band = q.find('bandwidth')
|
||||||
|
if band is not None:
|
||||||
|
in_qos = band.find('inbound')
|
||||||
|
if in_qos is not None:
|
||||||
|
in_av = in_qos.get('average')
|
||||||
|
in_peak = in_qos.get('peak')
|
||||||
|
in_burst = in_qos.get('burst')
|
||||||
|
in_floor = in_qos.get('floor')
|
||||||
|
bound_list.append({'direction': 'inbound', 'average': in_av, 'peak': in_peak, 'floor': in_floor, 'burst': in_burst})
|
||||||
|
|
||||||
|
out_qos = band.find('outbound')
|
||||||
|
if out_qos is not None:
|
||||||
|
out_av = out_qos.get('average')
|
||||||
|
out_peak = out_qos.get('peak')
|
||||||
|
out_burst = out_qos.get('burst')
|
||||||
|
bound_list.append({'direction': 'outbound', 'average': out_av, 'peak': out_peak, 'burst': out_burst})
|
||||||
|
qos_values[mac[0]] = bound_list
|
||||||
|
return qos_values
|
||||||
|
|
||||||
|
def set_qos(self, mac, direction, average, peak, burst):
|
||||||
|
if direction == "inbound":
|
||||||
|
xml = "<inbound average='{}' peak='{}' burst='{}'/>".format(average, peak, burst)
|
||||||
|
elif direction == "outbound":
|
||||||
|
xml = "<outbound average='{}' peak='{}' burst='{}'/>".format(average, peak, burst)
|
||||||
|
else:
|
||||||
|
raise Exception('Direction must be inbound or outbound')
|
||||||
|
|
||||||
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
|
|
||||||
|
macs = tree.xpath("/domain/devices/interface/mac")
|
||||||
|
for cur_mac in macs:
|
||||||
|
|
||||||
|
if cur_mac.get("address") == mac:
|
||||||
|
interface = cur_mac.getparent()
|
||||||
|
band = interface.find('bandwidth')
|
||||||
|
if band is None:
|
||||||
|
xml = "<bandwidth>" + xml + "</bandwidth>"
|
||||||
|
interface.append(etree.fromstring(xml))
|
||||||
|
else:
|
||||||
|
direct = band.find(direction)
|
||||||
|
if direct is not None:
|
||||||
|
parent = direct.getparent()
|
||||||
|
parent.remove(direct)
|
||||||
|
parent.append(etree.fromstring(xml))
|
||||||
|
else:
|
||||||
|
band.append(etree.fromstring(xml))
|
||||||
|
new_xml = etree.tostring(tree)
|
||||||
|
self.wvm.defineXML(new_xml)
|
||||||
|
|
||||||
|
def unset_qos(self, mac, direction):
|
||||||
|
tree = etree.fromstring(self._XMLDesc(0))
|
||||||
|
for direct in tree.xpath("/domain/devices/interface/bandwidth/{}".format(direction)):
|
||||||
|
band_el = direct.getparent()
|
||||||
|
interface_el = band_el.getparent() # parent bandwidth,it parent is interface
|
||||||
|
parent_mac = interface_el.xpath('mac/@address')
|
||||||
|
if parent_mac[0] == mac:
|
||||||
|
band_el.remove(direct)
|
||||||
|
|
||||||
|
self.wvm.defineXML(etree.tostring(tree))
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue