mirror of
https://github.com/retspen/webvirtcloud
synced 2026-03-23 11:04:49 +00:00
Merge ea4f2cba8b into 5c2232f4e8
This commit is contained in:
commit
27aec79af5
46 changed files with 4295 additions and 969 deletions
|
|
@ -17,7 +17,7 @@
|
|||
<h2 class="form-signin-heading">{% trans "Sign In" %}</h2>
|
||||
<input type="text" class="form-control" name="username" placeholder="Login" autocapitalize="none" autocorrect="off" autofocus>
|
||||
<input type="password" class="form-control" name="password" placeholder="Password">
|
||||
<input name="next" id="next" type="hidden" value="{% url 'instances' %}">
|
||||
<input name="next" id="next" type="hidden" value="{% url 'allinstances' %}">
|
||||
<button class="btn btn-lg btn-success btn-block" type="submit">{% trans "Sign In" %}</button>
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> {% trans "Overview" %}
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -20,6 +23,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -1,9 +1,26 @@
|
|||
from django.conf.urls import url
|
||||
from . import views
|
||||
from storages.views import storages, storage
|
||||
from networks.views import networks, network
|
||||
from secrets.views import secrets
|
||||
from create.views import create_instance
|
||||
from interfaces.views import interfaces, interface
|
||||
from computes.views import overview, compute_graph, computes
|
||||
from instances.views import instances
|
||||
from nwfilters.views import nwfilter, nwfilters
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.computes, name='computes'),
|
||||
url(r'^overview/(?P<compute_id>[0-9]+)/$', views.overview, name='overview'),
|
||||
url(r'^statistics/(?P<compute_id>[0-9]+)/$',
|
||||
views.compute_graph, name='compute_graph'),
|
||||
url(r'^/', computes, name='computes'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/$', overview, name='overview'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/statistics$', compute_graph, name='compute_graph'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/instances/$', instances, name='instances'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/storages/$', storages, name='storages'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/storage/(?P<pool>[\w\-\.\/]+)/$', storage, name='storage'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/networks/$', networks, name='networks'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/network/(?P<pool>[\w\-\.]+)/$', network, name='network'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/interfaces/$', interfaces, name='interfaces'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/interface/(?P<iface>[\w\-\.\:]+)/$', interface, name='interface'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/nwfilter/(?P<nwfltr>[\w\-\.\:]+)/$', nwfilter, name='nwfilter'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/secrets/$', secrets, name='secrets'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/create/$', create_instance, name='create_instance'),
|
||||
]
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ class NewVMForm(forms.Form):
|
|||
disk = forms.IntegerField(required=False)
|
||||
memory = forms.IntegerField(error_messages={'required': _('No RAM size has been entered')})
|
||||
networks = forms.CharField(error_messages={'required': _('No Network pool has been choice')})
|
||||
nwfilter = forms.CharField(required=False)
|
||||
storage = forms.CharField(max_length=20, required=False)
|
||||
template = forms.CharField(required=False)
|
||||
images = forms.CharField(required=False)
|
||||
|
|
|
|||
|
|
@ -107,6 +107,17 @@
|
|||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "NWFilter" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="nwfilter" class="form-control">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% for nwfilter in nwfilters %}
|
||||
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Video" %}</label>
|
||||
|
|
@ -226,6 +237,17 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "NWFilter" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="nwfilter" class="form-control">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% for nwfilter in nwfilters %}
|
||||
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "VirtIO" %}</label>
|
||||
<div class="col-sm-6">
|
||||
|
|
@ -379,6 +401,17 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "NWFilter" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="nwfilter" class="form-control">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% for nwfilter in nwfilters %}
|
||||
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "MAC" %}</label>
|
||||
<div class="col-sm-6">
|
||||
|
|
|
|||
|
|
@ -28,7 +28,6 @@ def create_instance(request, compute_id):
|
|||
storages = []
|
||||
networks = []
|
||||
meta_prealloc = False
|
||||
#computes = Compute.objects.all()
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
flavors = Flavor.objects.filter().order_by('id')
|
||||
|
||||
|
|
@ -40,6 +39,7 @@ def create_instance(request, compute_id):
|
|||
|
||||
storages = sorted(conn.get_storages(only_actives=True))
|
||||
networks = sorted(conn.get_networks())
|
||||
nwfilters = conn.get_nwfilters()
|
||||
instances = conn.get_instances()
|
||||
videos = conn.get_video()
|
||||
cache_modes = sorted(conn.get_cache_modes().items())
|
||||
|
|
@ -139,11 +139,11 @@ def create_instance(request, compute_id):
|
|||
try:
|
||||
conn.create_instance(data['name'], data['memory'], data['vcpu'], data['host_model'],
|
||||
uuid, volumes, data['cache_mode'], data['networks'], data['virtio'],
|
||||
data["listener_addr"], None, data["video"], data["console_pass"],
|
||||
data["listener_addr"], data["nwfilter"], data["video"], data["console_pass"],
|
||||
data['mac'])
|
||||
create_instance = Instance(compute_id=compute_id, name=data['name'], uuid=uuid)
|
||||
create_instance.save()
|
||||
messages.success(request,"Instance is created.")
|
||||
messages.success(request, _("Instance is created."))
|
||||
return HttpResponseRedirect(reverse('instance', args=[compute_id, data['name']]))
|
||||
except libvirtError as lib_err:
|
||||
if data['hdd_size'] or volumes[clone_path]:
|
||||
|
|
|
|||
|
|
@ -33,12 +33,24 @@
|
|||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="col-sm-4 control-label">{% trans "NWFilter" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select class="form-control" name="add-net-nwfilter">
|
||||
<option value="">{% trans "None" %}</option>
|
||||
{% for nwfilter in compute_nwfilters %}
|
||||
<option value="{{ nwfilter }}">{{ nwfilter }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</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="add_network">{% trans "Add" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div> <!-- /.modal -->
|
||||
|
|
|
|||
184
instances/templates/allinstances.html
Normal file
184
instances/templates/allinstances.html
Normal file
|
|
@ -0,0 +1,184 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}{% trans "Instances" %}{% endblock %}
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{% if request.user.is_superuser %}
|
||||
{% include 'create_inst_block.html' %}
|
||||
{% endif %}
|
||||
{% if all_host_vms or all_user_vms %}
|
||||
<div class="pull-right search">
|
||||
<input id="filter" class="form-control" type="text" placeholder="Search">
|
||||
</div>
|
||||
{% endif %}
|
||||
<h1 class="page-header">{% trans "Instances" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
{% include 'errors_block.html' %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="table-responsive">
|
||||
{% if request.user.is_superuser %}
|
||||
{% if not all_host_vms %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning:" %}</strong> {% trans "You don't have any Instance" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% ifequal view_style "nongrouped" %}
|
||||
{% include 'allinstances_index_nongrouped.html' %}
|
||||
{% endifequal %}
|
||||
{% ifequal view_style "grouped" %}
|
||||
{% include 'allinstances_index_grouped.html' %}
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if not all_user_vms %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning:" %}</strong> {% trans "You don't have any Instance" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<table class="table table-hover table-striped sortable-theme-bootstrap" data-sortable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th>VCPU</th>
|
||||
<th>Memory</th>
|
||||
<th data-sortable="false" style="width: 165px;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
{% for inst, vm in all_user_vms.items %}
|
||||
<tr>
|
||||
<td><a href="{% url 'instance' vm.compute_id vm.name %}">{{ vm.name }}</a><br><small><em>{{ vm.title }}</em></small></td>
|
||||
<td>{% ifequal vm.status 1 %}
|
||||
<span class="text-success">{% trans "Active" %}</span>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 5 %}
|
||||
<span class="text-danger">{% trans "Off" %}</span>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 3 %}
|
||||
<span class="text-warning">{% trans "Suspend" %}</span>
|
||||
{% endifequal %}
|
||||
</td>
|
||||
<td>{{ vm.vcpu }}</td>
|
||||
<td>{{ vm.memory }} {% trans "MB" %}</td>
|
||||
<td><form action="" method="post" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="name" value="{{ vm.name }}"/>
|
||||
<input type="hidden" name="compute_id" value="{{ vm.compute_id }}"/>
|
||||
{% ifequal vm.status 5 %}
|
||||
{% if inst.instance.is_template %}
|
||||
<button class="btn btn-sm btn-default" type="button" name="clone" title="{% trans "Clone" %}" onclick="goto_instance_clone({{ vm.compute_id }}, '{{ vm.name }}');">
|
||||
<span class="glyphicon glyphicon-duplicate"></span>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-default" type="submit" name="poweron" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Cycle" %}">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "VNC Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 3 %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Cycle" %}">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "VNC/Spice Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 1 %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="poweroff" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="powercycle" title="{% trans "Power Cycle" %}" onclick="return confirm('Are you sure?')">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<a href="#" class="btn btn-sm btn-default" onclick='open_console("{{ vm.compute_id }}-{{ vm.uuid }}")' title="{% trans "Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</a>
|
||||
{% endifequal %}
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script src="{% static "js/sortable.min.js" %}"></script>
|
||||
<script>
|
||||
function open_console(uuid) {
|
||||
window.open("{% url 'console' %}?token=" + uuid, "", "width=850,height=485");
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function filter_table() {
|
||||
var rex = new RegExp($(this).val(), 'i');
|
||||
$('.searchable tr').hide();
|
||||
$('.searchable tr').filter(function () {
|
||||
return rex.test($(this).text());
|
||||
}).show();
|
||||
Cookies.set("instances_filter", $(this).val(), { expires: 1 });
|
||||
}
|
||||
$(document).ready(function () {
|
||||
instances_filter_cookie = Cookies.get("instances_filter");
|
||||
if (instances_filter_cookie) {
|
||||
$('#filter').val(instances_filter_cookie);
|
||||
$('#filter').each(filter_table);
|
||||
}
|
||||
(function ($) {
|
||||
$('#filter').keyup(filter_table)
|
||||
}(jQuery));
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
function goto_instance_clone(compute, instance) {
|
||||
window.location = "/instances/" + compute + "/" + instance + "/#clone";
|
||||
}
|
||||
</script>
|
||||
{% if request.user.is_superuser %}
|
||||
<script>
|
||||
function goto_compute() {
|
||||
var compute = $("#compute_select").val();
|
||||
window.location.href = "{% url 'create_instance' 1 %}".replace(1, compute);
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
|
|
@ -833,39 +833,63 @@
|
|||
{% if request.user.is_superuser %}
|
||||
<div role="tabpanel" class="tab-pane tab-pane-bordered" id="network">
|
||||
<p>
|
||||
{% trans "Assign network device to bridge" %}
|
||||
{% include 'add_instance_network_block.html' %}
|
||||
{% trans "Assign network device to bridge" %}
|
||||
{% include 'add_instance_network_block.html' %}
|
||||
</p>
|
||||
<form class="form-horizontal" action="" method="post" role="form">{% csrf_token %}
|
||||
<p style="font-weight:bold;">{% trans "Network devices" %}</p>
|
||||
<p style="font-weight:bold;">{% trans "Network devices" %}</p>
|
||||
<div class="col-xs-12 col-sm-12">
|
||||
<form method="post" role="form">{% csrf_token %}
|
||||
{% for network in networks %}
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label" style="font-weight:normal;">eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</label>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" class="form-control" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
<label>eth{{ forloop.counter0 }}({{ network.target|default:"no target" }})</label>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<input type="text" class="form-control" name="net-source-{{ forloop.counter0 }}" value="{{ network.nic }}" disabled/>
|
||||
<div class="panel-body">
|
||||
<div class="form-group form-inline">
|
||||
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "MAC" %} </label>
|
||||
<input class="form-control" type="text" value="{{ network.mac }}" readonly/>
|
||||
<label class="control-label"><em>to</em></label>
|
||||
<input class="form-control" type="text" name="net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||||
</div>
|
||||
<div class="form-group form-inline">
|
||||
<label class="col-sm-2 col-sm-offset-1 control-label">{% trans "NIC" %} </label>
|
||||
<input class="form-control" type="text" value="{{ network.nic }}" readonly/>
|
||||
<label class="control-label"><em>to</em></label>
|
||||
<select class="form-control" name="net-source-{{ forloop.counter0 }}">
|
||||
{% for c_net in compute_networks %}
|
||||
<option value="net:{{ c_net }}" {% ifequal c_net network.nic %} selected {% endifequal %}>Network {{ c_net }}</option>
|
||||
{% endfor %}
|
||||
{% for c_iface in compute_interfaces %}
|
||||
<option value="iface:{{ c_iface }}" {% ifequal c_iface network.nic %} selected {% endifequal %}>Interface {{ c_iface }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group form-inline">
|
||||
<label class="col-sm-2 col-sm-offset-1">{% 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 compute_nwfilters %}
|
||||
<option value="{{ c_filters }}" {% ifequal c_filters network.filterref %} selected {% endifequal %}>{{ c_filters }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-sm-3">
|
||||
<select name="net-source-{{ forloop.counter0 }}" class="form-control" id="network_select" onchange="network_select_enable()">
|
||||
{% for c_nets in compute_networks %}
|
||||
<option value="net:{{ c_nets }}" {% if c_nets == network.nic %}selected{% endif %}>Network {{ c_nets }}</option>
|
||||
{% endfor %}
|
||||
{% for c_iface in compute_interfaces %}
|
||||
<option value="iface:{{ c_iface }}" {% if c_iface == network.nic %}selected{% endif %}>Interface {{ c_iface }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<div class="panel-footer">
|
||||
<button class="btn btn-sm btn-primary" name="change_network" title="{% trans "Change" %}">{% trans "Change" %}</button>
|
||||
<button class="btn btn-sm pull-right btn-danger" value="{{ network.mac }}" name="delete_network" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">{% trans "Delete" %}</button>
|
||||
</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% ifequal status 5 %}
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" id="btn_change_network" name="change_network" disabled>{% trans "Change" %}</button>
|
||||
{% else %}
|
||||
<button type="submit" class="btn btn-lg btn-success pull-right" id="btn_change_network" name="change_network" disabled>{% trans "Change" %}</button>
|
||||
{% endifequal %}
|
||||
</form>
|
||||
|
||||
|
||||
|
||||
</div>
|
||||
<div class="clearfix"></div>
|
||||
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if request.user.is_superuser or request.user.userattributes.can_clone_instances %}
|
||||
|
|
@ -1237,7 +1261,7 @@
|
|||
</script>
|
||||
<script>
|
||||
function random_mac(net) {
|
||||
$.getJSON('/instance/random_mac_address/', function(data) {
|
||||
$.getJSON('{% url 'random_mac_address' %}', function (data) {
|
||||
$('input[name="'+net+'"]').val(data['mac']);
|
||||
});
|
||||
};
|
||||
|
|
@ -1254,14 +1278,15 @@
|
|||
<script>
|
||||
function guess_mac_address(src_elem, net) {
|
||||
new_vname = $(src_elem).val();
|
||||
$.getJSON('/instance/guess_mac_address/' + new_vname + '/', function(data) {
|
||||
guess_mac_address_url = "{% url 'guess_mac_address' 1 %}".replace(1, new_vname);
|
||||
$.getJSON(guess_mac_address_url, function(data) {
|
||||
$('input[name="clone-net-mac-'+net+'"]').val(data['mac']);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
<script>
|
||||
function guess_clone_name() {
|
||||
$.getJSON('/instance/guess_clone_name/', function(data) {
|
||||
$.getJSON('{% url 'guess_clone_name' %}', function(data) {
|
||||
guessed_name = data['name'].split(".")[0];
|
||||
$('#clone_name').val(guessed_name);
|
||||
update_clone_disk_name(guessed_name);
|
||||
|
|
@ -1339,7 +1364,8 @@
|
|||
});
|
||||
$(document).ready(function () {
|
||||
// set vdi url
|
||||
$.get("/datasource/vdi/{{ vname }}/", function(data) {
|
||||
|
||||
$.get("{% url 'vdi_url' vname %}", function(data) {
|
||||
$("#vdi_url_input").attr("value", data);
|
||||
$("#vdi_url").attr("href", data);
|
||||
});
|
||||
|
|
@ -1370,12 +1396,6 @@
|
|||
});
|
||||
});
|
||||
</script>
|
||||
<script>
|
||||
function network_select_enable(){
|
||||
// set network button enabled
|
||||
$('button[name="change_network"]').removeAttr('disabled');
|
||||
}
|
||||
</script>
|
||||
<script src="{% static "js/Chart.min.js" %}"></script>
|
||||
<script>
|
||||
$('#chartgraphs').on('shown.bs.tab', function (event) {
|
||||
|
|
@ -1574,7 +1594,8 @@
|
|||
</script>
|
||||
<script>
|
||||
function update_logs_table(vname) {
|
||||
$.getJSON('/logs/vm_logs/'+vname+'/', function(data) {
|
||||
logurl = "{% url 'vm_logs' 1 %}".replace(1, vname);
|
||||
$.getJSON(logurl, function(data) {
|
||||
var logs = "";
|
||||
$.each(data, function(id) {
|
||||
row = data[id];
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}{% trans "Instances" %}{% endblock %}
|
||||
{% block title %}{% trans "Instances" %} - {{ compute.name }}{% endblock %}
|
||||
{% block style %}
|
||||
<link rel="stylesheet" href="{% static "css/sortable-theme-bootstrap.css" %}" />
|
||||
{% endblock %}
|
||||
{% block content %}
|
||||
<!-- Page Heading -->
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{% if request.user.is_superuser %}
|
||||
|
|
@ -17,129 +17,144 @@
|
|||
<input id="filter" class="form-control" type="text" placeholder="Search">
|
||||
</div>
|
||||
{% endif %}
|
||||
<h1 class="page-header">{% trans "Instances" %}</h1>
|
||||
<h1 class="page-header">{{ compute.name }}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
|
||||
{% include 'errors_block.html' %}
|
||||
<ol class="breadcrumb">
|
||||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> {% trans "Instances" %}
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-sitemap"></i> <a href="{% url 'networks' compute.id %}">{% trans "Networks" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
<div class="row">
|
||||
{% include 'errors_block.html' %}
|
||||
<div class="row">
|
||||
{% if not all_host_vms %}
|
||||
<div class="col-lg-12">
|
||||
<div class="table-responsive">
|
||||
{% if request.user.is_superuser %}
|
||||
{% if not all_host_vms %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning:" %}</strong> {% trans "You don't have any Instance" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
{% ifequal view_style "nongrouped" %}
|
||||
{% include 'instances_nongrouped.html' %}
|
||||
{% endifequal %}
|
||||
{% ifequal view_style "grouped" %}
|
||||
{% include 'instances_grouped.html' %}
|
||||
{% endifequal %}
|
||||
{% endif %}
|
||||
{% else %}
|
||||
{% if not all_user_vms %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning:" %}</strong> {% trans "You don't have any Instance" %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<table class="table table-hover table-striped sortable-theme-bootstrap" data-sortable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name</th>
|
||||
<th>Status</th>
|
||||
<th>VCPU</th>
|
||||
<th>Memory</th>
|
||||
<th data-sortable="false" style="width: 165px;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
{% for inst, vm in all_user_vms.items %}
|
||||
<tr>
|
||||
<td><a href="{% url 'instance' vm.compute_id vm.name %}">{{ vm.name }}</a><br><small><em>{{ vm.title }}</em></small></td>
|
||||
<td>{% ifequal vm.status 1 %}
|
||||
<span class="text-success">{% trans "Active" %}</span>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 5 %}
|
||||
<span class="text-danger">{% trans "Off" %}</span>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 3 %}
|
||||
<span class="text-warning">{% trans "Suspend" %}</span>
|
||||
{% endifequal %}
|
||||
</td>
|
||||
<td>{{ vm.vcpu }}</td>
|
||||
<td>{{ vm.memory }} {% trans "MB" %}</td>
|
||||
<td><form action="" method="post" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="name" value="{{ vm.name }}"/>
|
||||
<input type="hidden" name="compute_id" value="{{ vm.compute_id }}"/>
|
||||
{% ifequal vm.status 5 %}
|
||||
{% if inst.instance.is_template %}
|
||||
<button class="btn btn-sm btn-default" type="button" name="clone" title="{% trans "Clone" %}" onclick="goto_instance_clone({{ vm.compute_id }}, '{{ vm.name }}');">
|
||||
<span class="glyphicon glyphicon-duplicate"></span>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-default" type="submit" name="poweron" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Cycle" %}">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "VNC Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 3 %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Cycle" %}">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "VNC/Spice Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% ifequal vm.status 1 %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="poweroff" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="powercycle" title="{% trans "Power Cycle" %}" onclick="return confirm('Are you sure?')">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<a href="#" class="btn btn-sm btn-default" onclick='open_console("{{ vm.compute_id }}-{{ vm.uuid }}")' title="{% trans "Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</a>
|
||||
{% endifequal %}
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning:" %}</strong> {% trans "Hypervisor doesn't have any instances" %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-lg-12">
|
||||
<table class="table table-hover table-striped sortable-theme-bootstrap" data-sortable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Name<br>Description</th>
|
||||
<th>Host<br>User</th>
|
||||
<th>Status</th>
|
||||
<th>VCPU</th>
|
||||
<th>Memory</th>
|
||||
<th data-sortable="false" style="width:205px;">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
{% for host, inst in all_host_vms.items %}
|
||||
{% for vm, info in inst.items %}
|
||||
<tr>
|
||||
<td><a href="{% url 'instance' host.0 vm %}">{{ vm }}</a><br><small><em>{{ info.title }}</em></small></td>
|
||||
<td><a href="{% url 'overview' host.0 %}">{{ host.1 }}</a><br><small><em>{% if info.userinstances.count > 0 %}{{ info.userinstances.first_user.user.username }}{% if info.userinstances.count > 1 %} (+{{ info.userinstances.count|add:"-1" }}){% endif %}{% endif %}</em></small></td>
|
||||
<td>
|
||||
{% ifequal info.status 1 %}<span class="text-success">{% trans "Active" %}</span>{% endifequal %}
|
||||
{% ifequal info.status 5 %}<span class="text-danger">{% trans "Off" %}</span>{% endifequal %}
|
||||
{% ifequal info.status 3 %}<span class="text-warning">{% trans "Suspend" %}</span>{% endifequal %}
|
||||
</td>
|
||||
<td>{{ info.vcpu }}</td>
|
||||
<td>{{ info.memory|filesizeformat }}</td>
|
||||
<td><form action="" method="post" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="name" value="{{ vm }}"/>
|
||||
<input type="hidden" name="compute_id" value="{{ host.0 }}"/>
|
||||
{% ifequal info.status 5 %}
|
||||
{% if info.is_template %}
|
||||
<button class="btn btn-sm btn-default" type="button" name="clone" title="{% trans "Clone" %}" onclick="goto_instance_clone({{ host.0 }}, '{{ vm }}');">
|
||||
<span class="glyphicon glyphicon-duplicate"></span>
|
||||
</button>
|
||||
{% else %}
|
||||
<button class="btn btn-sm btn-default" type="submit" name="poweron" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
{% endif %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Suspend" %}">
|
||||
<span class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Cycle" %}">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "VNC Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% ifequal info.status 3 %}
|
||||
<button class="btn btn-sm btn-default" type="submit" name="resume" title="{% trans "Resume" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Suspend" %}">
|
||||
<span class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Off" %}">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power Cycle" %}">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "VNC Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</button>
|
||||
{% endifequal %}
|
||||
{% ifequal info.status 1 %}
|
||||
<button class="btn btn-sm btn-default disabled" title="{% trans "Power On" %}">
|
||||
<span class="glyphicon glyphicon-play"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="suspend" title="{% trans "Suspend" %}">
|
||||
<span class="glyphicon glyphicon-pause"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="poweroff" title="{% trans "Power Off" %}" onclick="return confirm('Are you sure?')">
|
||||
<span class="glyphicon glyphicon-off"></span>
|
||||
</button>
|
||||
<button class="btn btn-sm btn-default" type="submit" name="powercycle" title="{% trans "Power Cycle" %}" onclick="return confirm('Are you sure?')">
|
||||
<span class="glyphicon glyphicon-refresh"></span>
|
||||
</button>
|
||||
<a href="#" class="btn btn-sm btn-default" onclick='open_console("{{ host.0 }}-{{ info.uuid }}")' title="{% trans "Console" %}">
|
||||
<span class="glyphicon glyphicon-eye-open"></span>
|
||||
</a>
|
||||
{% endifequal %}
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block script %}
|
||||
<script src="{% static "js/sortable.min.js" %}"></script>
|
||||
|
|
@ -170,15 +185,15 @@
|
|||
</script>
|
||||
<script>
|
||||
function goto_instance_clone(compute, instance) {
|
||||
window.location = "/instance/" + compute + "/" + instance + "/#clone";
|
||||
window.location = "/instances/" + compute + "/" + instance + "/#clone";
|
||||
}
|
||||
</script>
|
||||
{% if request.user.is_superuser %}
|
||||
<script>
|
||||
function goto_compute() {
|
||||
var compute = $("#compute_select").val();
|
||||
window.location = "/compute/" + compute + "/create/";
|
||||
window.location.href = "{% url 'create_instance' 1 %}".replace(1, compute);
|
||||
}
|
||||
</script>
|
||||
{% endif %}
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
@ -2,6 +2,7 @@ from django.conf.urls import url
|
|||
from . import views
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', views.allinstances, name='allinstances'),
|
||||
url(r'^(?P<compute_id>[0-9]+)/(?P<vname>[\w\-\.]+)/$', views.instance, name='instance'),
|
||||
url(r'^statistics/(?P<compute_id>[0-9]+)/(?P<vname>[\w\-\.]+)/$', views.inst_graph, name='inst_graph'),
|
||||
url(r'^status/(?P<compute_id>[0-9]+)/(?P<vname>[\w\-\.]+)/$', views.inst_status, name='inst_status'),
|
||||
|
|
|
|||
|
|
@ -26,175 +26,72 @@ from logs.views import addlogmsg
|
|||
from django.conf import settings
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
@login_required
|
||||
def index(request):
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
|
||||
return HttpResponseRedirect(reverse('instances'))
|
||||
return HttpResponseRedirect(reverse('allinstances'))
|
||||
|
||||
|
||||
@login_required
|
||||
def instances(request):
|
||||
def allinstances(request):
|
||||
"""
|
||||
INSTANCES LIST FOR ALL HOSTS
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
all_host_vms = {}
|
||||
error_messages = []
|
||||
computes = Compute.objects.all().order_by("name")
|
||||
|
||||
if not request.user.is_superuser:
|
||||
all_user_vms = get_user_instances(request)
|
||||
else:
|
||||
for comp in computes:
|
||||
try:
|
||||
all_host_vms.update(get_host_instances(request,comp))
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
||||
if request.method == 'POST':
|
||||
try:
|
||||
instances_actions(request)
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
addlogmsg(request.user.username, instance.name, lib_err.message)
|
||||
|
||||
view_style = settings.VIEW_INSTANCES_LIST_STYLE
|
||||
|
||||
return render(request, 'allinstances.html', locals())
|
||||
|
||||
|
||||
@login_required
|
||||
def instances(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
|
||||
error_messages = []
|
||||
all_host_vms = {}
|
||||
all_user_vms = {}
|
||||
computes = Compute.objects.all().order_by("name")
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
def get_userinstances_info(instance):
|
||||
info = {}
|
||||
uis = UserInstance.objects.filter(instance=instance)
|
||||
info['count'] = uis.count()
|
||||
if info['count'] > 0:
|
||||
info['first_user'] = uis[0]
|
||||
else:
|
||||
info['first_user'] = None
|
||||
return info
|
||||
|
||||
def refresh_instance_database(comp, vm, info):
|
||||
instances = Instance.objects.filter(name=vm)
|
||||
if instances.count() > 1:
|
||||
for i in instances:
|
||||
user_instances_count = UserInstance.objects.filter(instance=i).count()
|
||||
if user_instances_count == 0:
|
||||
addlogmsg(request.user.username, i.name, _("Deleting due to multiple records."))
|
||||
i.delete()
|
||||
|
||||
try:
|
||||
check_uuid = Instance.objects.get(compute_id=comp["id"], name=vm)
|
||||
if check_uuid.uuid != info['uuid']:
|
||||
check_uuid.save()
|
||||
|
||||
all_host_vms[comp["id"],
|
||||
comp["name"],
|
||||
comp["status"],
|
||||
comp["cpu"],
|
||||
comp["mem_size"],
|
||||
comp["mem_perc"]][vm]['is_template'] = check_uuid.is_template
|
||||
all_host_vms[comp["id"],
|
||||
comp["name"],
|
||||
comp["status"],
|
||||
comp["cpu"],
|
||||
comp["mem_size"],
|
||||
comp["mem_perc"]][vm]['userinstances'] = get_userinstances_info(check_uuid)
|
||||
except Instance.DoesNotExist:
|
||||
check_uuid = Instance(compute_id=comp["id"], name=vm, uuid=info['uuid'])
|
||||
check_uuid.save()
|
||||
|
||||
if not request.user.is_superuser:
|
||||
user_instances = UserInstance.objects.filter(user_id=request.user.id)
|
||||
for usr_inst in user_instances:
|
||||
if connection_manager.host_is_up(usr_inst.instance.compute.type,
|
||||
usr_inst.instance.compute.hostname):
|
||||
conn = wvmHostDetails(usr_inst.instance.compute,
|
||||
usr_inst.instance.compute.login,
|
||||
usr_inst.instance.compute.password,
|
||||
usr_inst.instance.compute.type)
|
||||
all_user_vms[usr_inst] = conn.get_user_instances(usr_inst.instance.name)
|
||||
all_user_vms[usr_inst].update({'compute_id': usr_inst.instance.compute.id})
|
||||
all_user_vms = get_user_instances(request)
|
||||
else:
|
||||
for comp in computes:
|
||||
status = connection_manager.host_is_up(comp.type, comp.hostname)
|
||||
if status:
|
||||
try:
|
||||
conn = wvmHostDetails(comp, comp.login, comp.password, comp.type)
|
||||
comp_node_info = conn.get_node_info()
|
||||
comp_mem = conn.get_memory_usage()
|
||||
comp_instances = conn.get_host_instances(True)
|
||||
|
||||
if comp_instances:
|
||||
comp_info= {
|
||||
"id": comp.id,
|
||||
"name": comp.name,
|
||||
"status": status,
|
||||
"cpu": comp_node_info[3],
|
||||
"mem_size": comp_node_info[2],
|
||||
"mem_perc": comp_mem['percent']
|
||||
}
|
||||
all_host_vms[comp_info["id"], comp_info["name"], comp_info["status"], comp_info["cpu"],
|
||||
comp_info["mem_size"], comp_info["mem_perc"]] = comp_instances
|
||||
for vm, info in comp_instances.items():
|
||||
refresh_instance_database(comp_info, vm, info)
|
||||
|
||||
conn.close()
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
try:
|
||||
all_host_vms = get_host_instances(request, compute)
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
||||
if request.method == 'POST':
|
||||
name = request.POST.get('name', '')
|
||||
compute_id = request.POST.get('compute_id', '')
|
||||
instance = Instance.objects.get(compute_id=compute_id, name=name)
|
||||
try:
|
||||
conn = wvmInstances(instance.compute.hostname,
|
||||
instance.compute.login,
|
||||
instance.compute.password,
|
||||
instance.compute.type)
|
||||
if 'poweron' in request.POST:
|
||||
msg = _("Power On")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.start(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'poweroff' in request.POST:
|
||||
msg = _("Power Off")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.shutdown(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'powercycle' in request.POST:
|
||||
msg = _("Power Cycle")
|
||||
conn.force_shutdown(name)
|
||||
conn.start(name)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'getvvfile' in request.POST:
|
||||
msg = _("Send console.vv file")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
response = HttpResponse(content='', content_type='application/x-virt-viewer', status=200, reason=None, charset='utf-8')
|
||||
response.writelines('[virt-viewer]\n')
|
||||
response.writelines('type=' + conn.graphics_type(name) + '\n')
|
||||
response.writelines('host=' + conn.graphics_listen(name) + '\n')
|
||||
response.writelines('port=' + conn.graphics_port(name) + '\n')
|
||||
response.writelines('title=' + conn.domain_name(name) + '\n')
|
||||
response.writelines('password=' + conn.graphics_passwd(name) + '\n')
|
||||
response.writelines('enable-usbredir=1\n')
|
||||
response.writelines('disable-effects=all\n')
|
||||
response.writelines('secure-attention=ctrl+alt+ins\n')
|
||||
response.writelines('release-cursor=ctrl+alt\n')
|
||||
response.writelines('fullscreen=1\n')
|
||||
response.writelines('delete-this-file=1\n')
|
||||
response['Content-Disposition'] = 'attachment; filename="console.vv"'
|
||||
return response
|
||||
|
||||
if request.user.is_superuser:
|
||||
|
||||
if 'suspend' in request.POST:
|
||||
msg = _("Suspend")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.suspend(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'resume' in request.POST:
|
||||
msg = _("Resume")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.resume(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
instances_actions(request)
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
addlogmsg(request.user.username, instance.name, lib_err.message)
|
||||
|
||||
view_style = settings.VIEW_INSTANCES_LIST_STYLE
|
||||
|
||||
return render(request, 'instances.html', locals())
|
||||
|
||||
|
||||
|
|
@ -206,7 +103,7 @@ def instance(request, compute_id, vname):
|
|||
"""
|
||||
|
||||
error_messages = []
|
||||
#messages = []
|
||||
# messages = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
computes = Compute.objects.all().order_by('name')
|
||||
computes_count = computes.count()
|
||||
|
|
@ -217,8 +114,8 @@ def instance(request, compute_id, vname):
|
|||
console_listen_addresses = settings.QEMU_CONSOLE_LISTEN_ADDRESSES
|
||||
try:
|
||||
userinstance = UserInstance.objects.get(instance__compute_id=compute_id,
|
||||
instance__name=vname,
|
||||
user__id=request.user.id)
|
||||
instance__name=vname,
|
||||
user__id=request.user.id)
|
||||
except UserInstance.DoesNotExist:
|
||||
userinstance = None
|
||||
|
||||
|
|
@ -231,15 +128,15 @@ def instance(request, compute_id, vname):
|
|||
return 0
|
||||
size_str = size_str.encode('ascii', 'ignore').upper().translate(None, " B")
|
||||
if 'K' == size_str[-1]:
|
||||
return long(float(size_str[:-1]))<<10
|
||||
return long(float(size_str[:-1])) << 10
|
||||
elif 'M' == size_str[-1]:
|
||||
return long(float(size_str[:-1]))<<20
|
||||
return long(float(size_str[:-1])) << 20
|
||||
elif 'G' == size_str[-1]:
|
||||
return long(float(size_str[:-1]))<<30
|
||||
return long(float(size_str[:-1])) << 30
|
||||
elif 'T' == size_str[-1]:
|
||||
return long(float(size_str[:-1]))<<40
|
||||
return long(float(size_str[:-1])) << 40
|
||||
elif 'P' == size_str[-1]:
|
||||
return long(float(size_str[:-1]))<<50
|
||||
return long(float(size_str[:-1])) << 50
|
||||
else:
|
||||
return long(float(size_str))
|
||||
|
||||
|
|
@ -268,16 +165,16 @@ def instance(request, compute_id, vname):
|
|||
if connection_manager.host_is_up(usr_inst.instance.compute.type,
|
||||
usr_inst.instance.compute.hostname):
|
||||
conn = wvmInstance(usr_inst.instance.compute,
|
||||
usr_inst.instance.compute.login,
|
||||
usr_inst.instance.compute.password,
|
||||
usr_inst.instance.compute.type,
|
||||
usr_inst.instance.name)
|
||||
usr_inst.instance.compute.login,
|
||||
usr_inst.instance.compute.password,
|
||||
usr_inst.instance.compute.type,
|
||||
usr_inst.instance.name)
|
||||
cpu += int(conn.get_vcpu())
|
||||
memory += int(conn.get_memory())
|
||||
for disk in conn.get_disk_device():
|
||||
if disk['size']:
|
||||
disk_size += int(disk['size'])>>30
|
||||
|
||||
disk_size += int(disk['size']) >> 30
|
||||
|
||||
if ua.max_instances > 0 and instance > ua.max_instances:
|
||||
msg = "instance"
|
||||
if settings.QUOTA_DEBUG:
|
||||
|
|
@ -301,7 +198,7 @@ def instance(request, compute_id, vname):
|
|||
dev_base = "vd"
|
||||
else:
|
||||
dev_base = "sd"
|
||||
existing_devs = [ disk['dev'] for disk in disks ]
|
||||
existing_devs = [disk['dev'] for disk in disks]
|
||||
for l in string.lowercase:
|
||||
dev = dev_base + l
|
||||
if dev not in existing_devs:
|
||||
|
|
@ -348,6 +245,7 @@ def instance(request, compute_id, vname):
|
|||
vname)
|
||||
compute_networks = sorted(conn.get_networks())
|
||||
compute_interfaces = sorted(conn.get_ifaces())
|
||||
compute_nwfilters = conn.get_nwfilters()
|
||||
status = conn.get_status()
|
||||
autostart = conn.get_autostart()
|
||||
vcpu = conn.get_vcpu()
|
||||
|
|
@ -364,6 +262,7 @@ def instance(request, compute_id, vname):
|
|||
else:
|
||||
media_iso = []
|
||||
networks = conn.get_net_device()
|
||||
|
||||
vcpu_range = conn.get_max_cpus()
|
||||
memory_range = [256, 512, 768, 1024, 2048, 4096, 6144, 8192, 16384]
|
||||
if memory not in memory_range:
|
||||
|
|
@ -377,7 +276,7 @@ def instance(request, compute_id, vname):
|
|||
console_port = conn.get_console_port()
|
||||
console_keymap = conn.get_console_keymap()
|
||||
console_listen_address = conn.get_console_listen_addr()
|
||||
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)
|
||||
has_managed_save_image = conn.get_managed_save_image()
|
||||
console_passwd = conn.get_console_passwd()
|
||||
|
|
@ -387,6 +286,7 @@ def instance(request, compute_id, vname):
|
|||
cache_modes = sorted(conn.get_cache_modes().items())
|
||||
default_cache = settings.INSTANCE_VOLUME_DEFAULT_CACHE
|
||||
default_format = settings.INSTANCE_VOLUME_DEFAULT_FORMAT
|
||||
default_owner = settings.INSTANCE_VOLUME_DEFAULT_OWNER
|
||||
formats = conn.get_image_formats()
|
||||
|
||||
busses = conn.get_busses()
|
||||
|
|
@ -450,7 +350,8 @@ def instance(request, compute_id, vname):
|
|||
instance.delete()
|
||||
|
||||
try:
|
||||
del_userinstance = UserInstance.objects.filter(instance__compute_id=compute_id, instance__name=vname)
|
||||
del_userinstance = UserInstance.objects.filter(instance__compute_id=compute_id,
|
||||
instance__name=vname)
|
||||
del_userinstance.delete()
|
||||
except UserInstance.DoesNotExist:
|
||||
pass
|
||||
|
|
@ -458,7 +359,7 @@ def instance(request, compute_id, vname):
|
|||
msg = _("Destroy")
|
||||
addlogmsg(request.user.username, instance_name, msg)
|
||||
|
||||
return HttpResponseRedirect(reverse('instances'))
|
||||
return HttpResponseRedirect(reverse('allinstances'))
|
||||
|
||||
if 'rootpasswd' in request.POST:
|
||||
passwd = request.POST.get('passwd', '')
|
||||
|
|
@ -504,7 +405,8 @@ def instance(request, compute_id, vname):
|
|||
msg = _("Please shutdown down your instance and then try again")
|
||||
error_messages.append(msg)
|
||||
|
||||
if 'resize' in request.POST and (request.user.is_superuser or request.user.is_staff or userinstance.is_change):
|
||||
if 'resize' in request.POST and (
|
||||
request.user.is_superuser or request.user.is_staff or userinstance.is_change):
|
||||
new_vcpu = request.POST.get('vcpu', '')
|
||||
new_cur_vcpu = request.POST.get('cur_vcpu', '')
|
||||
new_memory = request.POST.get('memory', '')
|
||||
|
|
@ -518,13 +420,13 @@ def instance(request, compute_id, vname):
|
|||
disks_new = []
|
||||
for disk in disks:
|
||||
input_disk_size = filesizefstr(request.POST.get('disk_size_' + disk['dev'], ''))
|
||||
if input_disk_size > disk['size']+(64<<20):
|
||||
if input_disk_size > disk['size'] + (64 << 20):
|
||||
disk['size_new'] = input_disk_size
|
||||
disks_new.append(disk)
|
||||
disk_sum = sum([disk['size']>>30 for disk in disks_new])
|
||||
disk_new_sum = sum([disk['size_new']>>30 for disk in disks_new])
|
||||
quota_msg = check_user_quota(0, int(new_vcpu)-vcpu, int(new_memory)-memory, disk_new_sum-disk_sum)
|
||||
if not request.user.is_superuser and quota_msg:
|
||||
disks_new.append(disk)
|
||||
disk_sum = sum([disk['size'] >> 30 for disk in disks_new])
|
||||
disk_new_sum = sum([disk['size_new'] >> 30 for disk in disks_new])
|
||||
quota_msg = check_user_quota(0, int(new_vcpu) - vcpu, int(new_memory) - memory, disk_new_sum - disk_sum)
|
||||
if not request.user.is_superuser and quota_msg:
|
||||
msg = _("User %s quota reached, cannot resize '%s'!" % (quota_msg, instance.name))
|
||||
error_messages.append(msg)
|
||||
else:
|
||||
|
|
@ -539,19 +441,19 @@ def instance(request, compute_id, vname):
|
|||
|
||||
if 'addvolume' in request.POST and (request.user.is_superuser or userinstance.is_change):
|
||||
connCreate = wvmCreate(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
storage = request.POST.get('storage', '')
|
||||
name = request.POST.get('name', '')
|
||||
format = request.POST.get('format', '')
|
||||
format = request.POST.get('format', default_format)
|
||||
size = request.POST.get('size', 0)
|
||||
meta_prealloc = request.POST.get('meta_prealloc', False)
|
||||
bus = request.POST.get('bus', '')
|
||||
cache = request.POST.get('cache', '')
|
||||
bus = request.POST.get('bus', default_bus)
|
||||
cache = request.POST.get('cache', default_cache)
|
||||
target = get_new_disk_dev(disks, bus)
|
||||
|
||||
path = connCreate.create_volume(storage, name, size, format, meta_prealloc)
|
||||
|
||||
path = connCreate.create_volume(storage, name, size, format, meta_prealloc, default_owner)
|
||||
conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus)
|
||||
msg = _('Attach new disk')
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
|
|
@ -667,7 +569,7 @@ def instance(request, compute_id, vname):
|
|||
msg = _("Set VNC type")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#vncsettings')
|
||||
|
||||
|
||||
if 'set_console_listen_address' in request.POST:
|
||||
console_type = request.POST.get('console_listen_address', '')
|
||||
conn.set_console_listen_addr(console_type)
|
||||
|
|
@ -689,6 +591,7 @@ def instance(request, compute_id, vname):
|
|||
return HttpResponseRedirect(reverse('instance', args=[new_compute.id, vname]))
|
||||
|
||||
if 'change_network' in request.POST:
|
||||
msg = _("Change network")
|
||||
network_data = {}
|
||||
|
||||
for post in request.POST:
|
||||
|
|
@ -700,31 +603,43 @@ def instance(request, compute_id, vname):
|
|||
network_data[post] = request.POST.get(post, '')
|
||||
|
||||
conn.change_network(network_data)
|
||||
msg = _("Edit network")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
msg = _("Network Devices are changed. Please reboot instance to activate.")
|
||||
messages.success(request, msg)
|
||||
if conn.get_status() != 5: messages.success(request, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#network')
|
||||
|
||||
if 'add_network' in request.POST:
|
||||
msg = _("Add network")
|
||||
mac = request.POST.get('add-net-mac')
|
||||
nwfilter = request.POST.get('add-net-nwfilter')
|
||||
(source, source_type) = get_network_tuple(request.POST.get('add-net-network'))
|
||||
|
||||
conn.add_network(mac, source, source_type)
|
||||
msg = _("Edit network")
|
||||
conn.add_network(mac, source, source_type, nwfilter=nwfilter)
|
||||
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
msg = _("Network Devices are changed. Please reboot instance to activate.")
|
||||
messages.success(request, msg)
|
||||
msg = _("Network Device is added. Please reboot instance to activate.")
|
||||
if conn.get_status() != 5: messages.success(request, msg)
|
||||
|
||||
return HttpResponseRedirect(request.get_full_path() + '#network')
|
||||
|
||||
|
||||
if 'delete_network' in request.POST:
|
||||
msg = _("Delete network")
|
||||
mac_address = request.POST.get('delete_network', '')
|
||||
|
||||
conn.delete_network(mac_address)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
msg = _("Network Device is deleted. Please reboot instance to activate.")
|
||||
if conn.get_status() != 5: messages.success(request, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#network')
|
||||
|
||||
if 'add_owner' in request.POST:
|
||||
user_id = int(request.POST.get('user_id', ''))
|
||||
|
||||
|
||||
if settings.ALLOW_INSTANCE_MULTIPLE_OWNER:
|
||||
check_inst = UserInstance.objects.filter(instance=instance, user_id=user_id)
|
||||
else:
|
||||
check_inst = UserInstance.objects.filter(instance=instance)
|
||||
|
||||
|
||||
if check_inst:
|
||||
msg = _("Owner already added")
|
||||
error_messages.append(msg)
|
||||
|
|
@ -743,19 +658,18 @@ def instance(request, compute_id, vname):
|
|||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#users')
|
||||
|
||||
|
||||
if request.user.is_superuser or request.user.userattributes.can_clone_instances:
|
||||
if 'clone' in request.POST:
|
||||
clone_data = {}
|
||||
clone_data['name'] = request.POST.get('name', '')
|
||||
|
||||
disk_sum = sum([disk['size']>>30 for disk in disks])
|
||||
disk_sum = sum([disk['size'] >> 30 for disk in disks])
|
||||
quota_msg = check_user_quota(1, vcpu, memory, disk_sum)
|
||||
check_instance = Instance.objects.filter(name=clone_data['name'])
|
||||
|
||||
|
||||
for post in request.POST:
|
||||
clone_data[post] = request.POST.get(post, '').strip()
|
||||
|
||||
|
||||
if clone_instance_auto_name and not clone_data['name']:
|
||||
auto_vname = clone_free_names[0]
|
||||
clone_data['name'] = auto_vname
|
||||
|
|
@ -764,7 +678,7 @@ def instance(request, compute_id, vname):
|
|||
disk_dev = "disk-{}".format(disk['dev'])
|
||||
disk_name = get_clone_disk_name(disk, vname, auto_vname)
|
||||
clone_data[disk_dev] = disk_name
|
||||
|
||||
|
||||
if not request.user.is_superuser and quota_msg:
|
||||
msg = _("User %s quota reached, cannot create '%s'!" % (quota_msg, clone_data['name']))
|
||||
error_messages.append(msg)
|
||||
|
|
@ -774,14 +688,16 @@ def instance(request, compute_id, vname):
|
|||
elif not re.match(r'^[a-zA-Z0-9-]+$', clone_data['name']):
|
||||
msg = _("Instance name '%s' contains invalid characters!" % clone_data['name'])
|
||||
error_messages.append(msg)
|
||||
elif not re.match(r'^([0-9A-F]{2})(\:?[0-9A-F]{2}){5}$', clone_data['clone-net-mac-0'], re.IGNORECASE):
|
||||
elif not re.match(r'^([0-9A-F]{2})(\:?[0-9A-F]{2}){5}$', clone_data['clone-net-mac-0'],
|
||||
re.IGNORECASE):
|
||||
msg = _("Instance mac '%s' invalid format!" % clone_data['clone-net-mac-0'])
|
||||
error_messages.append(msg)
|
||||
else:
|
||||
new_uuid = conn.clone_instance(clone_data)
|
||||
new_instance = Instance(compute_id=compute_id, name=clone_data['name'], uuid=new_uuid)
|
||||
new_instance.save()
|
||||
userinstance = UserInstance(instance_id=new_instance.id, user_id=request.user.id, is_delete=True)
|
||||
userinstance = UserInstance(instance_id=new_instance.id, user_id=request.user.id,
|
||||
is_delete=True)
|
||||
userinstance.save()
|
||||
|
||||
msg = _("Clone of '%s'" % instance.name)
|
||||
|
|
@ -789,18 +705,19 @@ def instance(request, compute_id, vname):
|
|||
if settings.CLONE_INSTANCE_AUTO_MIGRATE:
|
||||
new_compute = Compute.objects.order_by('?').first()
|
||||
migrate_instance(new_compute, new_instance, xml_del=True, offline=True)
|
||||
return HttpResponseRedirect(reverse('instance', args=[new_instance.compute.id, new_instance.name]))
|
||||
return HttpResponseRedirect(
|
||||
reverse('instance', args=[new_instance.compute.id, new_instance.name]))
|
||||
|
||||
if 'change_options' in request.POST:
|
||||
instance.is_template = request.POST.get('is_template', False)
|
||||
instance.save()
|
||||
|
||||
|
||||
options = {}
|
||||
for post in request.POST:
|
||||
if post in ['title', 'description']:
|
||||
options[post] = request.POST.get(post, '')
|
||||
conn.set_options(options)
|
||||
|
||||
|
||||
msg = _("Edit options")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path() + '#options')
|
||||
|
|
@ -839,6 +756,154 @@ def inst_status(request, compute_id, vname):
|
|||
return response
|
||||
|
||||
|
||||
def get_host_instances(request,comp):
|
||||
|
||||
def refresh_instance_database(comp, inst_name, info):
|
||||
def get_userinstances_info(instance):
|
||||
info = {}
|
||||
uis = UserInstance.objects.filter(instance=instance)
|
||||
info['count'] = uis.count()
|
||||
if info['count'] > 0:
|
||||
info['first_user'] = uis[0]
|
||||
else:
|
||||
info['first_user'] = None
|
||||
return info
|
||||
|
||||
instances = Instance.objects.filter(name=inst_name)
|
||||
if instances.count() > 1:
|
||||
for i in instances:
|
||||
user_instances_count = UserInstance.objects.filter(instance=i).count()
|
||||
if user_instances_count == 0:
|
||||
addlogmsg(request.user.username, i.name, _("Deleting due to multiple records."))
|
||||
i.delete()
|
||||
|
||||
try:
|
||||
inst_on_db = Instance.objects.get(compute_id=comp["id"], name=inst_name)
|
||||
if inst_on_db.uuid != info['uuid']:
|
||||
inst_on_db.save()
|
||||
|
||||
all_host_vms[comp["id"],
|
||||
comp["name"],
|
||||
comp["status"],
|
||||
comp["cpu"],
|
||||
comp["mem_size"],
|
||||
comp["mem_perc"]][inst_name]['is_template'] = inst_on_db.is_template
|
||||
all_host_vms[comp["id"],
|
||||
comp["name"],
|
||||
comp["status"],
|
||||
comp["cpu"],
|
||||
comp["mem_size"],
|
||||
comp["mem_perc"]][inst_name]['userinstances'] = get_userinstances_info(inst_on_db)
|
||||
except Instance.DoesNotExist:
|
||||
inst_on_db = Instance(compute_id=comp["id"], name=inst_name, uuid=info['uuid'])
|
||||
inst_on_db.save()
|
||||
|
||||
all_host_vms = {}
|
||||
status = connection_manager.host_is_up(comp.type, comp.hostname)
|
||||
|
||||
if status:
|
||||
|
||||
conn = wvmHostDetails(comp, comp.login, comp.password, comp.type)
|
||||
comp_node_info = conn.get_node_info()
|
||||
comp_mem = conn.get_memory_usage()
|
||||
comp_instances = conn.get_host_instances(True)
|
||||
|
||||
if comp_instances:
|
||||
comp_info = {
|
||||
"id": comp.id,
|
||||
"name": comp.name,
|
||||
"status": status,
|
||||
"cpu": comp_node_info[3],
|
||||
"mem_size": comp_node_info[2],
|
||||
"mem_perc": comp_mem['percent']
|
||||
}
|
||||
all_host_vms[comp_info["id"], comp_info["name"], comp_info["status"], comp_info["cpu"],
|
||||
comp_info["mem_size"], comp_info["mem_perc"]] = comp_instances
|
||||
for vm, info in comp_instances.items():
|
||||
refresh_instance_database(comp_info, vm, info)
|
||||
|
||||
conn.close()
|
||||
|
||||
return all_host_vms
|
||||
|
||||
def get_user_instances(request):
|
||||
all_user_vms = {}
|
||||
user_instances = UserInstance.objects.filter(user_id=request.user.id)
|
||||
for usr_inst in user_instances:
|
||||
if connection_manager.host_is_up(usr_inst.instance.compute.type,
|
||||
usr_inst.instance.compute.hostname):
|
||||
conn = wvmHostDetails(usr_inst.instance.compute,
|
||||
usr_inst.instance.compute.login,
|
||||
usr_inst.instance.compute.password,
|
||||
usr_inst.instance.compute.type)
|
||||
all_user_vms[usr_inst] = conn.get_user_instances(usr_inst.instance.name)
|
||||
all_user_vms[usr_inst].update({'compute_id': usr_inst.instance.compute.id})
|
||||
return all_user_vms
|
||||
|
||||
|
||||
def instances_actions(request):
|
||||
name = request.POST.get('name', '')
|
||||
compute_id = request.POST.get('compute_id', '')
|
||||
instance = Instance.objects.get(compute_id=compute_id, name=name)
|
||||
|
||||
conn = wvmInstances(instance.compute.hostname,
|
||||
instance.compute.login,
|
||||
instance.compute.password,
|
||||
instance.compute.type)
|
||||
if 'poweron' in request.POST:
|
||||
msg = _("Power On")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.start(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'poweroff' in request.POST:
|
||||
msg = _("Power Off")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.shutdown(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'powercycle' in request.POST:
|
||||
msg = _("Power Cycle")
|
||||
conn.force_shutdown(name)
|
||||
conn.start(name)
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'getvvfile' in request.POST:
|
||||
msg = _("Send console.vv file")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
response = HttpResponse(content='', content_type='application/x-virt-viewer', status=200, reason=None,
|
||||
charset='utf-8')
|
||||
response.writelines('[virt-viewer]\n')
|
||||
response.writelines('type=' + conn.graphics_type(name) + '\n')
|
||||
response.writelines('host=' + conn.graphics_listen(name) + '\n')
|
||||
response.writelines('port=' + conn.graphics_port(name) + '\n')
|
||||
response.writelines('title=' + conn.domain_name(name) + '\n')
|
||||
response.writelines('password=' + conn.graphics_passwd(name) + '\n')
|
||||
response.writelines('enable-usbredir=1\n')
|
||||
response.writelines('disable-effects=all\n')
|
||||
response.writelines('secure-attention=ctrl+alt+ins\n')
|
||||
response.writelines('release-cursor=ctrl+alt\n')
|
||||
response.writelines('fullscreen=1\n')
|
||||
response.writelines('delete-this-file=1\n')
|
||||
response['Content-Disposition'] = 'attachment; filename="console.vv"'
|
||||
return response
|
||||
|
||||
if request.user.is_superuser:
|
||||
|
||||
if 'suspend' in request.POST:
|
||||
msg = _("Suspend")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.suspend(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
if 'resume' in request.POST:
|
||||
msg = _("Resume")
|
||||
addlogmsg(request.user.username, instance.name, msg)
|
||||
conn.resume(name)
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
|
||||
|
||||
@login_required
|
||||
def inst_graph(request, compute_id, vname):
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -19,6 +22,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -21,6 +24,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> {% trans "Interfaces" %}
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -10,6 +10,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -19,6 +22,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -20,6 +23,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
0
nwfilters/__init__.py
Normal file
0
nwfilters/__init__.py
Normal file
6
nwfilters/admin.py
Normal file
6
nwfilters/admin.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
8
nwfilters/apps.py
Normal file
8
nwfilters/apps.py
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class NwfiltersConfig(AppConfig):
|
||||
name = 'nwfilters'
|
||||
0
nwfilters/migrations/__init__.py
Normal file
0
nwfilters/migrations/__init__.py
Normal file
6
nwfilters/models.py
Normal file
6
nwfilters/models.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
32
nwfilters/templates/create_nwfilter_block.html
Normal file
32
nwfilters/templates/create_nwfilter_block.html
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
{% load i18n %}
|
||||
{% if request.user.is_superuser %}
|
||||
<a href="#AddNWFilter" type="button" class="btn btn-success pull-right" data-toggle="modal">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||
</a>
|
||||
|
||||
<!-- Modal Secret -->
|
||||
<div class="modal fade" id="AddNWFilter" tabindex="-1" role="dialog" aria-labelledby="AddNWFilter" 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 "Create New NWFilter" %}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<div class="col-xs-12" id="xmlheight">
|
||||
<input type="hidden" name="nwfilter_xml"/>
|
||||
<textarea id="editor" name="from_xml"></textarea>
|
||||
</div>
|
||||
</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="create_nwfilter">{% trans "Create" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div>
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
{% endif %}
|
||||
223
nwfilters/templates/nwfilter.html
Normal file
223
nwfilters/templates/nwfilter.html
Normal file
|
|
@ -0,0 +1,223 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %}
|
||||
{% block content %}
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{% include 'create_nwfilter_block.html' %}
|
||||
<h1 class="page-header">{% trans "NWFilter:" %} {{ name }}</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-sitemap"></i> <a href="{% url 'networks' compute.id %}">{% trans "Networks" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
{% include 'errors_block.html' %}
|
||||
{% include 'messages_block.html' %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-6 col-sm-4">
|
||||
<p>{% trans "UUID:" %}</p>
|
||||
<p>{% trans "Name:" %}</p>
|
||||
</div>
|
||||
|
||||
<div class="col-xs-6 col-sm-8">
|
||||
<p>{{ uuid }}</p>
|
||||
<p>{{ name }}</p>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<p><strong>{% trans "XML:" %}</strong></p>
|
||||
<form class="form-inline" method="post" role="form">{% csrf_token %}
|
||||
<div class="col-xs-12" id="xmlheight">
|
||||
<input type="hidden" name="edit_xml"/>
|
||||
<textarea id="edit_editor">{{ xml }}</textarea>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary pull-right" name="edit_nwfilter">
|
||||
{% trans "Edit" %}
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p><strong>{% trans "Filter References:" %}</strong></p>
|
||||
<form class="form-inline pull-right" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<label>{% trans "Filter:" %}</label>
|
||||
<select id="nwfilter_select" name="nwfilters_select" class="form-control">
|
||||
<option value="" selected>None</option>
|
||||
{% for nwf in nwfilters_all %}
|
||||
<option value="{{ nwf.name }}">{{ nwf.name }}</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
||||
<button type="submit" class="btn btn-success pull-right" name="add_nwfilter_ref">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 45px;">#</th>
|
||||
<th>{% trans "Reference" %}</th>
|
||||
<th colspan="3">{% trans "Action" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for ref in refs %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ ref }}</td>
|
||||
<td style="width:30px;">
|
||||
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="ref" value="{{ ref }}">
|
||||
<button type="submit" class="btn btn-sm btn-default" name="del_nwfilter_ref" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<p><strong>{% trans "Rules:" %}</strong></p>
|
||||
<a href="#AddNWFilterRule" type="button" class="btn btn-success pull-right" data-toggle="modal">
|
||||
<span class="glyphicon glyphicon-plus" aria-hidden="true"></span>
|
||||
</a>
|
||||
|
||||
<!-- Modal Secret -->
|
||||
<div class="modal fade" id="AddNWFilterRule" tabindex="-1" role="dialog" aria-labelledby="AddNWFilterRule" 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 New NWFilter Rule" %}</h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
<div class="form-group">
|
||||
<div class="col-xs-12" id="xmlheight">
|
||||
<input type="hidden" name="nwfilterrule_xml"/>
|
||||
<textarea id="rule_editor"></textarea>
|
||||
</div>
|
||||
<p><small><em>If there is a rule which has same attributes it replaces that rule...</em></small></p>
|
||||
</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="add_nwfilter_rule">{% trans "Add" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div>
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div><!-- /.modal -->
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 45px;">{% trans "Rule" %}</th>
|
||||
<th>{% trans "ActionType" %}</th>
|
||||
<th>{% trans "Direction" %}</th>
|
||||
<th>{% trans "Priority" %}</th>
|
||||
<th>{% trans "Statematch" %}</th>
|
||||
<th>{% trans "Directives" %}</th>
|
||||
<th colspan="3">{% trans "Action" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for rule in rules %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td>{{ rule.action }}</td>
|
||||
<td>{{ rule.direction }}</td>
|
||||
<td>{{ rule.priority }}</td>
|
||||
<td>{{ rule.statematch }}</td>
|
||||
<td>{{ rule.directives }}</td>
|
||||
<td style="width:30px;">
|
||||
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="action" value="{{ rule.action }}">
|
||||
<input type="hidden" name="direction" value="{{ rule.direction }}">
|
||||
<input type="hidden" name="priority" value="{{ rule.priority }}">
|
||||
<button type="submit" class="btn btn-sm btn-default" name="del_nwfilter_rule" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{% static "js/sortable.min.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
(function ($) {
|
||||
$('#filter').keyup(function () {
|
||||
var rex = new RegExp($(this).val(), 'i');
|
||||
$('.searchable tr').hide();
|
||||
$('.searchable tr').filter(function () {
|
||||
return rex.test($(this).text());
|
||||
}).show();
|
||||
})
|
||||
}(jQuery));
|
||||
});
|
||||
</script>
|
||||
<script src="{% static "js/ace.js" %}"></script>
|
||||
<script>
|
||||
var editor = ace.edit("edit_editor");
|
||||
editor.getSession().setMode("ace/mode/xml");
|
||||
|
||||
var edit_input = $('input[name="edit_xml"]');
|
||||
editor.getSession().on("change",function () {
|
||||
edit_input.val(editor.getSession().getValue());
|
||||
})
|
||||
|
||||
var rule_editor = ace.edit("rule_editor");
|
||||
rule_editor.getSession().setMode("ace/mode/xml");
|
||||
|
||||
var rule_input = $('input[name="nwfilterrule_xml"]');
|
||||
rule_editor.getSession().on("change",function () {
|
||||
rule_input.val(rule_editor.getSession().getValue());
|
||||
})
|
||||
</script>
|
||||
|
||||
{% endblock %}
|
||||
171
nwfilters/templates/nwfilters.html
Normal file
171
nwfilters/templates/nwfilters.html
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
{% extends "base.html" %}
|
||||
{% load i18n %}
|
||||
{% load staticfiles %}
|
||||
{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %}
|
||||
{% block content %}
|
||||
<!-- Page Heading -->
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
{% include 'create_nwfilter_block.html' %}
|
||||
<h1 class="page-header">{{ compute.name }}</h1>
|
||||
<ol class="breadcrumb">
|
||||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-sitemap"></i> <a href="{% url 'networks' compute.id %}">{% trans "Networks" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> {% trans "NWFilters" %}
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.row -->
|
||||
|
||||
{% include 'errors_block.html' %}
|
||||
{% include 'messages_block.html' %}
|
||||
|
||||
<div class="row">
|
||||
<div class="col-lg-12">
|
||||
<div class="row">
|
||||
<div class="pull-right">
|
||||
<input id="filter" class="form-control" type="text" placeholder="Search">
|
||||
</div>
|
||||
<h3 class="page-header">{% trans "NWFilters" %}</h3>
|
||||
|
||||
</div>
|
||||
{% if nwfilters %}
|
||||
<div class="table-responsive">
|
||||
<table class="table table-striped sortable-theme-bootstrap" data-sortable>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style="width: 45px;">#</th>
|
||||
<th>{% trans "UUID" %}</th>
|
||||
<th>{% trans "Name" %}</th>
|
||||
<th data-sortable="false" colspan="3">{% trans "Action" %}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="searchable">
|
||||
{% for nwfilter in nwfilters %}
|
||||
<tr>
|
||||
<td>{{ forloop.counter }}</td>
|
||||
<td><a href="{% url "nwfilter" compute.id nwfilter.name %} ">{{ nwfilter.uuid }}</a></td>
|
||||
<td>{{ nwfilter.name }}</td>
|
||||
<td style="width:30px;">
|
||||
<div class="modal fade" id="Show{{ forloop.counter }}" tabindex="-1" role="dialog" aria-labelledby="showNWFilter" 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 "Details of NWFilter" %}: <span class="text-danger">{{ nwfilter.name }}</span></h4>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<pre>
|
||||
<code>
|
||||
{{ nwfilter.xml }}
|
||||
</code>
|
||||
</pre>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-default" data-dismiss="modal">{% trans "Close" %}</button>
|
||||
</div>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div> <!-- /.modal -->
|
||||
<a data-toggle="modal" href="#Show{{ forloop.counter }}" class="btn btn-sm btn-default" title="{% trans "Show" %}"><i class="fa fa-eye"></i></a>
|
||||
</td>
|
||||
<td style="width:30px;">
|
||||
<div class="modal fade" id="Clone{{ forloop.counter }}" tabindex="-1" role="dialog" aria-labelledby="addNwFilterLabel" 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 "Clone nwfilter" %} <span class="text-danger">{{ nwfilter.name }}</span></h4>
|
||||
</div>
|
||||
<form class="form-horizontal" method="post" role="form">{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label class="col-sm-3 control-label">{% trans "Name" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" name="cln_name" placeholder="{% trans "Name" %}" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
<input type="hidden" name="nwfiltername" value="{{ nwfilter.name }}">
|
||||
</div>
|
||||
</div>
|
||||
</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="cln_nwfilter">{% trans "Clone" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div> <!-- /.modal-content -->
|
||||
</div> <!-- /.modal-dialog -->
|
||||
</div> <!-- /.modal -->
|
||||
<a data-toggle="modal" href="#Clone{{ forloop.counter }}" class="btn btn-sm btn-default" title="{% trans "Clone" %}"><i class="fa fa-files-o"></i></a>
|
||||
</td>
|
||||
<td style="width:30px;">
|
||||
<form action="" method="post" style="height:10px" role="form">{% csrf_token %}
|
||||
<input type="hidden" name="nwfiltername" value="{{ nwfilter.name }}">
|
||||
<button type="submit" class="btn btn-sm btn-default" name="del_nwfilter" title="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
<i class="fa fa-trash"></i>
|
||||
</button>
|
||||
</form>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
{% else %}
|
||||
<div class="col-lg-12">
|
||||
<div class="alert alert-warning alert-dismissable">
|
||||
<button type="button" class="close" data-dismiss="alert" aria-hidden="true">×</button>
|
||||
<i class="fa fa-exclamation-triangle"></i> <strong>{% trans "Warning:" %}</strong> {% trans "Hypervisor doesn't have any NWFilters" %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block script %}
|
||||
<script src="{% static "js/sortable.min.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
(function ($) {
|
||||
$('#filter').keyup(function () {
|
||||
var rex = new RegExp($(this).val(), 'i');
|
||||
$('.searchable tr').hide();
|
||||
$('.searchable tr').filter(function () {
|
||||
return rex.test($(this).text());
|
||||
}).show();
|
||||
})
|
||||
}(jQuery));
|
||||
});
|
||||
</script>
|
||||
|
||||
<script src="{% static "js/ace.js" %}"></script>
|
||||
<script>
|
||||
var editor = ace.edit("editor");
|
||||
editor.getSession().setMode("ace/mode/xml");
|
||||
|
||||
var input = $('input[name="nwfilter_xml"]');
|
||||
editor.getSession().on("change",function () {
|
||||
input.val(editor.getSession().getValue());
|
||||
})
|
||||
</script>
|
||||
|
||||
|
||||
{% endblock %}
|
||||
6
nwfilters/tests.py
Normal file
6
nwfilters/tests.py
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
211
nwfilters/views.py
Normal file
211
nwfilters/views.py
Normal file
|
|
@ -0,0 +1,211 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
from __future__ import unicode_literals
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.shortcuts import render, get_object_or_404
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.urlresolvers import reverse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from computes.models import Compute
|
||||
from vrtManager import util
|
||||
from vrtManager.nwfilters import wvmNWFilters, wvmNWFilter
|
||||
from vrtManager.instance import wvmInstances, wvmInstance
|
||||
from libvirt import libvirtError
|
||||
from logs.views import addlogmsg
|
||||
|
||||
|
||||
@login_required
|
||||
def nwfilters(request, compute_id):
|
||||
"""
|
||||
:param request:
|
||||
:return:
|
||||
"""
|
||||
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
error_messages = []
|
||||
nwfilters_all = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
conn = wvmNWFilters(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
|
||||
if request.method == 'POST':
|
||||
if 'create_nwfilter' in request.POST:
|
||||
xml = request.POST.get('nwfilter_xml', '')
|
||||
if xml:
|
||||
try:
|
||||
util.etree.fromstring(xml)
|
||||
name = util.get_xml_path(xml, '/filter/@name')
|
||||
uuid = util.get_xml_path(xml, '/filter/uuid')
|
||||
except util.etree.ParseError:
|
||||
name = None
|
||||
|
||||
for nwf in nwfilters:
|
||||
if name == nwf.name():
|
||||
error_msg = _("A network filter with this name already exists")
|
||||
raise Exception(error_msg)
|
||||
if uuid == nwf.UUIDString():
|
||||
error_msg = _("A network filter with this uuid already exists")
|
||||
raise Exception(error_msg)
|
||||
else:
|
||||
try:
|
||||
msg = _("Creating NWFilter: %s" % name)
|
||||
conn.create_nwfilter(xml)
|
||||
addlogmsg(request.user.username, compute.hostname, msg)
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err.message)
|
||||
addlogmsg(request.user.username, compute.hostname, lib_err.message)
|
||||
|
||||
if 'del_nwfilter' in request.POST:
|
||||
name = request.POST.get('nwfiltername','')
|
||||
msg = _("Deleting NWFilter: %s" % name)
|
||||
in_use = False
|
||||
nwfilter = conn.get_nwfilter(name)
|
||||
|
||||
is_conn = wvmInstances(compute.hostname, compute.login, compute.password, compute.type)
|
||||
instances = is_conn.get_instances()
|
||||
for inst in instances:
|
||||
# if in_use: break
|
||||
i_conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, inst)
|
||||
dom_filterrefs = i_conn.get_filterrefs()
|
||||
|
||||
if name in dom_filterrefs:
|
||||
in_use = True
|
||||
msg = _("NWFilter is in use by %s. Cannot be deleted." % inst)
|
||||
error_messages.append(msg)
|
||||
addlogmsg(request.user.username, compute.hostname, msg)
|
||||
i_conn.close()
|
||||
break
|
||||
|
||||
is_conn.close()
|
||||
if nwfilter and not in_use:
|
||||
nwfilter.undefine()
|
||||
addlogmsg(request.user.username, compute.hostname, msg)
|
||||
|
||||
if 'cln_nwfilter' in request.POST:
|
||||
|
||||
name = request.POST.get('nwfiltername','')
|
||||
cln_name = request.POST.get('cln_name', name + '-clone')
|
||||
|
||||
conn.clone_nwfilter(name,cln_name)
|
||||
msg = _("Cloning NWFilter %s as %s" % (name, cln_name))
|
||||
addlogmsg(request.user.username, compute.hostname, msg)
|
||||
|
||||
for nwf in conn.get_nwfilters():
|
||||
nwfilters_all.append(conn.get_nwfilter_info(nwf))
|
||||
|
||||
conn.close()
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
addlogmsg(request.user.username, compute.hostname, lib_err)
|
||||
except Exception as err:
|
||||
error_messages.append(err)
|
||||
addlogmsg(request.user.username, compute.hostname, err)
|
||||
|
||||
return render(request, 'nwfilters.html', {'error_messages': error_messages,
|
||||
'nwfilters': nwfilters_all,
|
||||
'compute': compute})
|
||||
|
||||
|
||||
@login_required
|
||||
def nwfilter(request, compute_id, nwfltr):
|
||||
|
||||
error_messages = []
|
||||
nwfilters_all = []
|
||||
compute = get_object_or_404(Compute, pk=compute_id)
|
||||
|
||||
try:
|
||||
nwfilter = wvmNWFilter(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type,
|
||||
nwfltr)
|
||||
conn = wvmNWFilters(compute.hostname,
|
||||
compute.login,
|
||||
compute.password,
|
||||
compute.type)
|
||||
|
||||
for nwf in conn.get_nwfilters():
|
||||
nwfilters_all.append(conn.get_nwfilter_info(nwf))
|
||||
|
||||
uuid = nwfilter.get_uuid()
|
||||
name = nwfilter.get_name()
|
||||
xml = nwfilter.get_xml()
|
||||
rules = nwfilter.get_rules()
|
||||
refs = nwfilter.get_filter_refs()
|
||||
|
||||
if request.method == 'POST':
|
||||
|
||||
if 'edit_nwfilter' in request.POST:
|
||||
new_xml = request.POST.get('edit_xml', '')
|
||||
|
||||
if new_xml:
|
||||
nwfilter.delete()
|
||||
try:
|
||||
conn.create_nwfilter(new_xml)
|
||||
except libvirtError as lib_err:
|
||||
conn.create_nwfilter(xml)
|
||||
raise libvirtError(lib_err)
|
||||
|
||||
if 'del_nwfilter_rule' in request.POST:
|
||||
action = request.POST.get('action', '')
|
||||
direction = request.POST.get('direction', '')
|
||||
priority = request.POST.get('priority', '')
|
||||
|
||||
new_xml = nwfilter.delete_rule(action, direction, priority)
|
||||
nwfilter.delete()
|
||||
try:
|
||||
conn.create_nwfilter(new_xml)
|
||||
except libvirtError as lib_err:
|
||||
conn.create_nwfilter(xml)
|
||||
raise libvirtError(lib_err)
|
||||
|
||||
if 'del_nwfilter_ref' in request.POST:
|
||||
ref_name = request.POST.get('ref')
|
||||
new_xml = nwfilter.delete_ref(ref_name)
|
||||
nwfilter.delete()
|
||||
try:
|
||||
conn.create_nwfilter(new_xml)
|
||||
except libvirtError as lib_err:
|
||||
conn.create_nwfilter(xml)
|
||||
raise libvirtError(lib_err)
|
||||
|
||||
if 'add_nwfilter_rule' in request.POST:
|
||||
rule_xml = request.POST.get('nwfilterrule_xml', '')
|
||||
if not rule_xml:
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
new_xml = nwfilter.add_rule(rule_xml)
|
||||
nwfilter.delete()
|
||||
try:
|
||||
conn.create_nwfilter(new_xml)
|
||||
except libvirtError as lib_err:
|
||||
conn.create_nwfilter(xml)
|
||||
raise libvirtError(lib_err)
|
||||
|
||||
if 'add_nwfilter_ref' in request.POST:
|
||||
ref_name = request.POST.get('nwfilters_select', '')
|
||||
if not ref_name:
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
new_xml = nwfilter.add_ref(ref_name)
|
||||
nwfilter.delete()
|
||||
try:
|
||||
conn.create_nwfilter(new_xml)
|
||||
except libvirtError as lib_err:
|
||||
conn.create_nwfilter(xml)
|
||||
raise libvirtError(lib_err)
|
||||
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
conn.close()
|
||||
nwfilter.close()
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
except Exception as error_msg:
|
||||
error_messages.append(error_msg)
|
||||
|
||||
return render(request, 'nwfilter.html', locals())
|
||||
|
|
@ -15,6 +15,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -24,6 +27,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> {% trans "Secrets" %}
|
||||
</li>
|
||||
|
|
|
|||
4
static/css/font-awesome.min.css
vendored
Normal file → Executable file
4
static/css/font-awesome.min.css
vendored
Normal file → Executable file
File diff suppressed because one or more lines are too long
BIN
static/fonts/FontAwesome.otf
Normal file → Executable file
BIN
static/fonts/FontAwesome.otf
Normal file → Executable file
Binary file not shown.
BIN
static/fonts/fontawesome-webfont.eot
Normal file → Executable file
BIN
static/fonts/fontawesome-webfont.eot
Normal file → Executable file
Binary file not shown.
3230
static/fonts/fontawesome-webfont.svg
Normal file → Executable file
3230
static/fonts/fontawesome-webfont.svg
Normal file → Executable file
File diff suppressed because it is too large
Load diff
|
Before Width: | Height: | Size: 306 KiB After Width: | Height: | Size: 434 KiB |
BIN
static/fonts/fontawesome-webfont.ttf
Normal file → Executable file
BIN
static/fonts/fontawesome-webfont.ttf
Normal file → Executable file
Binary file not shown.
BIN
static/fonts/fontawesome-webfont.woff
Normal file → Executable file
BIN
static/fonts/fontawesome-webfont.woff
Normal file → Executable file
Binary file not shown.
BIN
static/fonts/fontawesome-webfont.woff2
Normal file → Executable file
BIN
static/fonts/fontawesome-webfont.woff2
Normal file → Executable file
Binary file not shown.
|
|
@ -16,6 +16,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> <a href="{% url 'storages' compute.id %}">{% trans "Storages" %}</a>
|
||||
</li>
|
||||
|
|
@ -25,6 +28,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@
|
|||
<li class="active">
|
||||
<i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-server"></i> <a href="{% url 'instances' compute.id %}">{% trans "Instances" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-hdd-o"></i> {% trans "Storages" %}
|
||||
</li>
|
||||
|
|
@ -20,6 +23,9 @@
|
|||
<li>
|
||||
<i class="fa fa-wifi"></i> <a href="{% url 'interfaces' compute.id %}">{% trans "Interfaces" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-filter"></i> <a href="{% url 'nwfilters' compute.id %}">{% trans "NWFilters" %}</a>
|
||||
</li>
|
||||
<li>
|
||||
<i class="fa fa-key"></i> <a href="{% url 'secrets' compute.id %}">{% trans "Secrets" %}</a>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ def storage(request, compute_id, pool):
|
|||
meta_prealloc = True
|
||||
try:
|
||||
conn.create_volume(data['name'], data['size'], data['format'], meta_prealloc)
|
||||
messages.success("Image file {} is created successfully".format(data['name']+".img"))
|
||||
messages.success(request, _("Image file {} is created successfully".format(data['name']+".img")))
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
|
@ -167,7 +167,7 @@ def storage(request, compute_id, pool):
|
|||
try:
|
||||
vol = conn.get_volume(volname)
|
||||
vol.delete(0)
|
||||
messages.success(request,_('Volume: {} is deleted.'.format(volname)))
|
||||
messages.success(request, _('Volume: {} is deleted.'.format(volname)))
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err.message)
|
||||
|
|
@ -197,8 +197,7 @@ def storage(request, compute_id, pool):
|
|||
format = None
|
||||
try:
|
||||
conn.clone_volume(data['image'], data['name'], format, meta_prealloc)
|
||||
messages.success(request, _("{} image cloned as {} successfully".format(data['image'],
|
||||
data['name'] + ".img")))
|
||||
messages.success(request, _("{} image cloned as {} successfully".format(data['image'], data['name'] + ".img")))
|
||||
return HttpResponseRedirect(request.get_full_path())
|
||||
except libvirtError as lib_err:
|
||||
error_messages.append(lib_err)
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav">
|
||||
<li {% class_active request "^/instance" %}>
|
||||
<a href="{% url 'instances' %}"><i class="fa fa-fw fa-desktop"></i> {% trans "Instances" %}</a>
|
||||
<a href="{% url 'allinstances' %}"><i class="fa fa-fw fa-desktop"></i> {% trans "Instances" %}</a>
|
||||
</li>
|
||||
{% if request.user.is_superuser %}
|
||||
<li {% class_active request "^/compute" %}{% class_active request "^/create" %}>
|
||||
|
|
|
|||
|
|
@ -389,6 +389,12 @@ class wvmConnect(object):
|
|||
interface.append(inface)
|
||||
return interface
|
||||
|
||||
def get_nwfilters(self):
|
||||
nwfilters = []
|
||||
for nwfilter in self.wvm.listNWFilters():
|
||||
nwfilters.append(nwfilter)
|
||||
return nwfilters
|
||||
|
||||
def get_cache_modes(self):
|
||||
"""Get cache available modes"""
|
||||
return {
|
||||
|
|
@ -443,7 +449,6 @@ class wvmConnect(object):
|
|||
|
||||
def get_video(self):
|
||||
""" Get available graphics video types """
|
||||
|
||||
def get_video_list(ctx):
|
||||
result = []
|
||||
for video_enum in ctx.xpath('/domainCapabilities/devices/video/enum'):
|
||||
|
|
@ -470,6 +475,9 @@ class wvmConnect(object):
|
|||
def get_network(self, net):
|
||||
return self.wvm.networkLookupByName(net)
|
||||
|
||||
def get_nwfilter(self, name):
|
||||
return self.wvm.nwfilterLookupByName(name)
|
||||
|
||||
def get_instance(self, name):
|
||||
return self.wvm.lookupByName(name)
|
||||
|
||||
|
|
|
|||
|
|
@ -187,6 +187,19 @@ class wvmInstance(wvmConnect):
|
|||
title = util.get_xml_path(self._XMLDesc(0), "/domain/title")
|
||||
return title if title else ''
|
||||
|
||||
def get_filterrefs(self):
|
||||
|
||||
def filterrefs(ctx):
|
||||
result = []
|
||||
for net in ctx.xpath('/domain/devices/interface'):
|
||||
filterref = net.xpath('filterref/@filter')
|
||||
if filterref:
|
||||
result.append(filterref[0])
|
||||
return result
|
||||
|
||||
return util.get_xml_path(self._XMLDesc(0), func=filterrefs)
|
||||
|
||||
|
||||
def get_description(self):
|
||||
description = util.get_xml_path(self._XMLDesc(0), "/domain/description")
|
||||
return description if description else ''
|
||||
|
|
@ -219,12 +232,13 @@ class wvmInstance(wvmConnect):
|
|||
mac_host = net.xpath('mac/@address')[0]
|
||||
network_host = net.xpath('source/@network|source/@bridge|source/@dev')[0]
|
||||
target_host = '' 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]
|
||||
try:
|
||||
net = self.get_network(network_host)
|
||||
ip = get_mac_ipaddr(net, mac_host)
|
||||
except libvirtError as e:
|
||||
ip = None
|
||||
result.append({'mac': mac_host, 'nic': network_host, 'target': target_host,'ip': ip})
|
||||
result.append({'mac': mac_host, 'nic': network_host, 'target': target_host,'ip': ip, 'filterref': filterref_host})
|
||||
return result
|
||||
|
||||
return util.get_xml_path(self._XMLDesc(0), func=networks)
|
||||
|
|
@ -487,8 +501,7 @@ class wvmInstance(wvmConnect):
|
|||
return self._defineXML(newxml)
|
||||
|
||||
def get_console_socket(self):
|
||||
socket = util.get_xml_path(self._XMLDesc(0),
|
||||
"/domain/devices/graphics/@socket")
|
||||
socket = util.get_xml_path(self._XMLDesc(0), "/domain/devices/graphics/@socket")
|
||||
return socket
|
||||
|
||||
def get_console_type(self):
|
||||
|
|
@ -700,13 +713,11 @@ class wvmInstance(wvmConnect):
|
|||
source_file = elm.get('file')
|
||||
if source_file:
|
||||
clone_dev_path.append(source_file)
|
||||
clone_path = os.path.join(os.path.dirname(source_file),
|
||||
target_file)
|
||||
clone_path = os.path.join(os.path.dirname(source_file), target_file)
|
||||
elm.set('file', clone_path)
|
||||
|
||||
vol = self.get_volume_by_path(source_file)
|
||||
vol_format = util.get_xml_path(vol.XMLDesc(0),
|
||||
"/volume/target/format/@type")
|
||||
vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||
|
||||
if vol_format == 'qcow2' and meta_prealloc:
|
||||
meta_prealloc = True
|
||||
|
|
@ -729,8 +740,7 @@ class wvmInstance(wvmConnect):
|
|||
elm.set('name', clone_name)
|
||||
|
||||
vol = self.get_volume_by_path(source_name)
|
||||
vol_format = util.get_xml_path(vol.XMLDesc(0),
|
||||
"/volume/target/format/@type")
|
||||
vol_format = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type")
|
||||
|
||||
vol_clone_xml = """
|
||||
<volume type='network'>
|
||||
|
|
@ -776,7 +786,7 @@ class wvmInstance(wvmConnect):
|
|||
bridge_name = net.bridgeName()
|
||||
return bridge_name
|
||||
|
||||
def add_network(self, mac_address, source, source_type='net', interface_type='bridge', model='virtio'):
|
||||
def add_network(self, mac_address, source, source_type='net', interface_type='bridge', model='virtio', nwfilter=None):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
bridge_name = self.get_bridge_name(source, source_type)
|
||||
xml_interface = """
|
||||
|
|
@ -784,8 +794,13 @@ class wvmInstance(wvmConnect):
|
|||
<mac address='%s'/>
|
||||
<source bridge='%s'/>
|
||||
<model type='%s'/>
|
||||
</interface>
|
||||
""" % (interface_type, mac_address, bridge_name, model)
|
||||
""" % (interface_type, mac_address, bridge_name, model)
|
||||
if nwfilter:
|
||||
xml_interface += """
|
||||
<filterref filter='%s'/>
|
||||
""" % nwfilter
|
||||
xml_interface += """</interface>"""
|
||||
|
||||
if self.get_status() == 5:
|
||||
devices = tree.find('devices')
|
||||
elm_interface = ElementTree.fromstring(xml_interface)
|
||||
|
|
@ -793,20 +808,42 @@ class wvmInstance(wvmConnect):
|
|||
xmldom = ElementTree.tostring(tree)
|
||||
self._defineXML(xmldom)
|
||||
|
||||
def delete_network(self, mac_address):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
devices = tree.find('devices')
|
||||
for interface in tree.findall('devices/interface'):
|
||||
source = interface.find('mac')
|
||||
if source.get('address', '') == mac_address:
|
||||
source = None
|
||||
devices.remove(interface)
|
||||
new_xml = ElementTree.tostring(tree)
|
||||
self._defineXML(new_xml)
|
||||
|
||||
def change_network(self, network_data):
|
||||
xml = self._XMLDesc(VIR_DOMAIN_XML_SECURE)
|
||||
tree = ElementTree.fromstring(xml)
|
||||
|
||||
for num, interface in enumerate(tree.findall('devices/interface')):
|
||||
net_source = network_data['net-source-' + str(num)]
|
||||
net_source_type = network_data['net-source-' + str(num) + '-type']
|
||||
net_mac = network_data['net-mac-' + str(num)]
|
||||
net_filter = network_data['net-nwfilter-' + str(num)]
|
||||
bridge_name = self.get_bridge_name(net_source, net_source_type)
|
||||
if interface.get('type') == 'bridge':
|
||||
source = interface.find('mac')
|
||||
source.set('address', net_mac)
|
||||
source = interface.find('source')
|
||||
source.set('bridge', bridge_name)
|
||||
source = interface.find('filterref')
|
||||
|
||||
if net_filter:
|
||||
if source is not None: source.set('filter', net_filter)
|
||||
else:
|
||||
element = ElementTree.Element("filterref")
|
||||
element.attrib['filter'] = net_filter
|
||||
interface.append(element)
|
||||
else:
|
||||
if source is not None: interface.remove(source)
|
||||
|
||||
new_xml = ElementTree.tostring(tree)
|
||||
self._defineXML(new_xml)
|
||||
|
||||
|
|
|
|||
125
vrtManager/nwfilters.py
Normal file
125
vrtManager/nwfilters.py
Normal file
|
|
@ -0,0 +1,125 @@
|
|||
from vrtManager.connection import wvmConnect
|
||||
from xml.etree import ElementTree
|
||||
|
||||
|
||||
class wvmNWFilters(wvmConnect):
|
||||
def get_nwfilter_info(self, name):
|
||||
nwfilter = self.get_nwfilter(name)
|
||||
xml = nwfilter.XMLDesc(0)
|
||||
uuid = nwfilter.UUIDString()
|
||||
return {'name': name, 'uuid': uuid, 'xml': xml}
|
||||
|
||||
def create_nwfilter(self, xml):
|
||||
self.wvm.nwfilterDefineXML(xml)
|
||||
|
||||
def clone_nwfilter(self,name, cln_name):
|
||||
nwfilter = self.get_nwfilter(name)
|
||||
if nwfilter:
|
||||
tree = ElementTree.fromstring(nwfilter.XMLDesc(0))
|
||||
tree.set('name', cln_name)
|
||||
uuid = tree.find('uuid')
|
||||
tree.remove(uuid)
|
||||
self.create_nwfilter(ElementTree.tostring(tree))
|
||||
|
||||
|
||||
class wvmNWFilter(wvmConnect):
|
||||
def __init__(self, host, login, passwd, conn, nwfiltername):
|
||||
wvmConnect.__init__(self, host, login, passwd, conn)
|
||||
self.nwfilter = self.get_nwfilter(nwfiltername)
|
||||
|
||||
def _XMLDesc(self, flags):
|
||||
return self.nwfilter.XMLDesc(flags)
|
||||
|
||||
def get_uuid(self):
|
||||
return self.nwfilter.UUIDString()
|
||||
|
||||
def get_name(self):
|
||||
return self.nwfilter.name()
|
||||
|
||||
def delete(self):
|
||||
self.nwfilter.undefine()
|
||||
|
||||
def get_xml(self):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
uuid = tree.find('uuid')
|
||||
tree.remove(uuid)
|
||||
return ElementTree.tostring(tree)
|
||||
|
||||
def get_filter_refs(self):
|
||||
refs = []
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
for ref in tree.findall("./filterref"):
|
||||
refs.append(ref.get('filter'))
|
||||
return refs
|
||||
|
||||
def get_rules(self):
|
||||
rules = []
|
||||
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
for r in tree.findall("./rule"):
|
||||
rule_action = r.get('action')
|
||||
rule_direction = r.get('direction')
|
||||
rule_priority = r.get('priority')
|
||||
rule_statematch = r.get('statematch')
|
||||
|
||||
rule_directives = r.find("./")
|
||||
if rule_directives is not None:
|
||||
rule_directives = ElementTree.tostring(rule_directives)
|
||||
|
||||
rule_info = {
|
||||
"action": rule_action,
|
||||
"direction": rule_direction,
|
||||
"priority": rule_priority,
|
||||
"statematch": rule_statematch,
|
||||
"directives": rule_directives
|
||||
}
|
||||
|
||||
rules.append(rule_info)
|
||||
|
||||
return rules
|
||||
|
||||
def delete_ref(self, name):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
for ref in tree.findall("./filterref"):
|
||||
if name == ref.get('filter'):
|
||||
tree.remove(ref)
|
||||
break
|
||||
return ElementTree.tostring(tree)
|
||||
|
||||
def delete_rule(self, action, direction, priority):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
|
||||
rule_tree = tree.findall("./rule[@action='%s'][@direction='%s'][@priority='%s']" % (action, direction, priority))
|
||||
if rule_tree:
|
||||
tree.remove(rule_tree[0])
|
||||
|
||||
return ElementTree.tostring(tree)
|
||||
|
||||
def add_ref(self, name):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
element = ElementTree.Element("filterref")
|
||||
element.attrib['filter'] = name
|
||||
tree.append(element)
|
||||
return ElementTree.tostring(tree)
|
||||
|
||||
def add_rule(self, xml):
|
||||
tree = ElementTree.fromstring(self._XMLDesc(0))
|
||||
rule = ElementTree.fromstring(xml)
|
||||
|
||||
rule_action = rule.get('action')
|
||||
rule_direction = rule.get('direction')
|
||||
rule_priority = rule.get('priority')
|
||||
rule_directives = rule.find("./")
|
||||
rule_tree = tree.findall("./rule[@action='%s'][@direction='%s'][@priority='%s']" % (rule_action, rule_direction, rule_priority))
|
||||
|
||||
if rule_tree:
|
||||
rule_tree[0].append(rule_directives)
|
||||
else:
|
||||
element = ElementTree.Element("rule")
|
||||
element.attrib['action'] = rule_action
|
||||
element.attrib['direction'] = rule_direction
|
||||
element.attrib['priority'] = rule_priority
|
||||
element.append(rule_directives)
|
||||
tree.append(element)
|
||||
|
||||
return ElementTree.tostring(tree)
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
from vrtManager import util
|
||||
from vrtManager.connection import wvmConnect
|
||||
from webvirtcloud.settings import INSTANCE_VOLUME_DEFAULT_OWNER as owner
|
||||
|
||||
|
||||
class wvmStorages(wvmConnect):
|
||||
|
|
@ -205,7 +206,7 @@ class wvmStorage(wvmConnect):
|
|||
)
|
||||
return vol_list
|
||||
|
||||
def create_volume(self, name, size, vol_fmt='qcow2', metadata=False):
|
||||
def create_volume(self, name, size, vol_fmt='qcow2', metadata=False, owner=owner):
|
||||
size = int(size) * 1073741824
|
||||
storage_type = self.get_type()
|
||||
alloc = size
|
||||
|
|
@ -222,8 +223,8 @@ class wvmStorage(wvmConnect):
|
|||
<target>
|
||||
<format type='%s'/>
|
||||
<permissions>
|
||||
<owner>107</owner>
|
||||
<group>107</group>
|
||||
<owner>%s</owner>
|
||||
<group>%s</group>
|
||||
<mode>0644</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>
|
||||
|
|
@ -232,10 +233,10 @@ class wvmStorage(wvmConnect):
|
|||
<lazy_refcounts/>
|
||||
</features>
|
||||
</target>
|
||||
</volume>""" % (name, size, alloc, vol_fmt)
|
||||
</volume>""" % (name, size, alloc, vol_fmt, owner['uid'], owner['guid'])
|
||||
self._createXML(xml, metadata)
|
||||
|
||||
def clone_volume(self, name, target_file, vol_fmt=None, metadata=False):
|
||||
def clone_volume(self, name, target_file, vol_fmt=None, metadata=False, owner=owner):
|
||||
storage_type = self.get_type()
|
||||
if storage_type == 'dir':
|
||||
target_file += '.img'
|
||||
|
|
@ -250,8 +251,8 @@ class wvmStorage(wvmConnect):
|
|||
<target>
|
||||
<format type='%s'/>
|
||||
<permissions>
|
||||
<owner>107</owner>
|
||||
<group>107</group>
|
||||
<owner>%s</owner>
|
||||
<group>%s</group>
|
||||
<mode>0644</mode>
|
||||
<label>virt_image_t</label>
|
||||
</permissions>
|
||||
|
|
@ -260,5 +261,5 @@ class wvmStorage(wvmConnect):
|
|||
<lazy_refcounts/>
|
||||
</features>
|
||||
</target>
|
||||
</volume>""" % (target_file, vol_fmt)
|
||||
</volume>""" % (target_file, vol_fmt, owner['uid'],owner['guid'])
|
||||
self._createXMLFrom(xml, vol, metadata)
|
||||
|
|
|
|||
|
|
@ -19,11 +19,13 @@ INSTALLED_APPS = (
|
|||
'django.contrib.sessions',
|
||||
'django.contrib.messages',
|
||||
'django.contrib.staticfiles',
|
||||
'dashboards',
|
||||
'computes',
|
||||
'console',
|
||||
'networks',
|
||||
'storages',
|
||||
'interfaces',
|
||||
'nwfilters',
|
||||
'instances',
|
||||
'secrets',
|
||||
'logs',
|
||||
|
|
@ -151,3 +153,5 @@ VIEW_INSTANCES_LIST_STYLE = 'grouped'
|
|||
INSTANCE_VOLUME_DEFAULT_FORMAT = 'qcow2'
|
||||
INSTANCE_VOLUME_DEFAULT_BUS = 'virtio'
|
||||
INSTANCE_VOLUME_DEFAULT_CACHE = 'directsync'
|
||||
# up to os, 0=root, 107=qemu or libvirt-bin(for ubuntu)
|
||||
INSTANCE_VOLUME_DEFAULT_OWNER = {'uid': 0, 'guid': 0}
|
||||
|
|
|
|||
|
|
@ -1,32 +1,18 @@
|
|||
from django.conf.urls import include, url
|
||||
|
||||
from instances.views import instances, instance, index
|
||||
from storages.views import storages, storage
|
||||
from networks.views import networks, network
|
||||
from secrets.views import secrets
|
||||
from create.views import create_instance
|
||||
from interfaces.views import interfaces, interface
|
||||
from instances.views import index
|
||||
from console.views import console
|
||||
# from django.contrib import admin
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^$', index, name='index'),
|
||||
url(r'^instances/$', instances, name='instances'),
|
||||
|
||||
url(r'^instance/', include('instances.urls')),
|
||||
url(r'^instances/', include('instances.urls')),
|
||||
url(r'^accounts/', include('accounts.urls')),
|
||||
url(r'^computes/', include('computes.urls')),
|
||||
url(r'^logs/', include('logs.urls')),
|
||||
url(r'^datasource/', include('datasource.urls')),
|
||||
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/storages/$', storages, name='storages'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/storage/(?P<pool>[\w\-\.\/]+)/$', storage, name='storage'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/networks/$', networks, name='networks'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/network/(?P<pool>[\w\-\.]+)/$', network, name='network'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/interfaces/$', interfaces, name='interfaces'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/interface/(?P<iface>[\w\-\.\:]+)/$', interface, name='interface'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/secrets/$', secrets, name='secrets'),
|
||||
url(r'^compute/(?P<compute_id>[0-9]+)/create/$', create_instance, name='create_instance'),
|
||||
|
||||
url(r'^console/$', console, name='console'),
|
||||
# (r'^admin/', include(admin.site.urls)),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue