From 40738d792017e4a7642733c47a7512c20adc74a7 Mon Sep 17 00:00:00 2001 From: Bandic007 <r.v.mirchev@gmail.com> Date: Thu, 27 Sep 2018 11:54:11 +0300 Subject: [PATCH] Additional changes --- computes/templates/overview.html | 3 + computes/urls.py | 23 ++- computes/views.py | 22 +++ console/templates/console-vnc-full.html | 4 +- console/templates/console-vnc-lite.html | 3 +- console/views.py | 5 +- instances/templates/compute_instances.html | 199 +++++++++++++++++++++ instances/templates/instances_grouped.html | 1 + instances/views.py | 13 +- interfaces/templates/interfaces.html | 5 +- networks/templates/networks.html | 5 +- nwfilters/templates/nwfilters.html | 3 + secrets/templates/secrets.html | 7 +- static/js/sortable.min.js | 2 +- storages/templates/storage.html | 2 +- storages/templates/storages.html | 5 +- webvirtcloud/urls.py | 6 + 17 files changed, 289 insertions(+), 19 deletions(-) create mode 100644 instances/templates/compute_instances.html diff --git a/computes/templates/overview.html b/computes/templates/overview.html index 89251cc..466c10e 100644 --- a/computes/templates/overview.html +++ b/computes/templates/overview.html @@ -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 'compute_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> diff --git a/computes/urls.py b/computes/urls.py index 58a0497..4b4ab6d 100644 --- a/computes/urls.py +++ b/computes/urls.py @@ -1,9 +1,22 @@ 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 +from instances.views import instances 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'^(?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='compute_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]+)/secrets/$', secrets, name='secrets'), + url(r'^(?P<compute_id>[0-9]+)/create/$', create_instance, name='create_instance'), ] diff --git a/computes/views.py b/computes/views.py index 18ad680..93e3f5e 100644 --- a/computes/views.py +++ b/computes/views.py @@ -134,6 +134,28 @@ def computes(request): error_messages.append(msg_err.as_text()) return render(request, 'computes.html', locals()) +@login_required +def compute_instances(request, compute_id): + """ + :param request: + :return: + """ + if not request.user.is_superuser: + return HttpResponseRedirect(reverse('index')) + error_messages = [] + compute = get_object_or_404(Compute, pk=compute_id) + try: + conn = wvmHostDetails(compute.hostname, + compute.login, + compute.password, + compute.type) + hostname, host_arch, host_memory, logical_cpu, model_cpu, uri_conn = conn.get_node_info() + hypervisor = conn.hypervisor_type() + mem_usage = conn.get_memory_usage() + conn.close() + except libvirtError as lib_err: + error_messages.append(lib_err) + return render(request, 'compute_instances.html', locals()) @login_required def overview(request, compute_id): diff --git a/console/templates/console-vnc-full.html b/console/templates/console-vnc-full.html index 6149289..ff6ee98 100755 --- a/console/templates/console-vnc-full.html +++ b/console/templates/console-vnc-full.html @@ -233,7 +233,7 @@ </li> <li> <label for="noVNC_setting_host">Host:</label> - <input id="noVNC_setting_host" value="{{ ws_host }}"/> + <input id="noVNC_setting_host" value="{{ ws_host }}{{ ws_path }}"/> </li> <li> <label for="noVNC_setting_port">Port:</label> @@ -332,4 +332,4 @@ <source src="{% static "js/novnc/app/sounds/bell.oga" %}" type="audio/ogg"> <source src="{% static "js/novnc/app/sounds/bell.mp3" %}" type="audio/mpeg"> </audio> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/console/templates/console-vnc-lite.html b/console/templates/console-vnc-lite.html index 4dd7bfe..0502a62 100755 --- a/console/templates/console-vnc-lite.html +++ b/console/templates/console-vnc-lite.html @@ -220,6 +220,7 @@ //var port = WebUtil.getConfigVar('port', window.location.port); var host = '{{ ws_host }}'; var port = '{{ ws_port }}'; + var wspath = '{{ ws_path }}'; // if port == 80 (or 443) then it won't be present and should be // set manually @@ -263,7 +264,7 @@ url = 'ws'; } - url += '://' + host; + url += '://' + host + wspath; if(port) { url += ':' + port; } diff --git a/console/views.py b/console/views.py index 4196ff0..70d0186 100644 --- a/console/views.py +++ b/console/views.py @@ -7,6 +7,8 @@ from instances.models import Instance from vrtManager.instance import wvmInstance from webvirtcloud.settings import WS_PORT from webvirtcloud.settings import WS_PUBLIC_HOST +from webvirtcloud.settings import WS_PUBLIC_PORT +from webvirtcloud.settings import WS_PUBLIC_PATH from libvirt import libvirtError @@ -40,8 +42,9 @@ def console(request): console_websocket_port = None console_passwd = None - ws_port = console_websocket_port if console_websocket_port else WS_PORT + ws_port = console_websocket_port if console_websocket_port else WS_PUBLIC_PORT ws_host = WS_PUBLIC_HOST if WS_PUBLIC_HOST else request.get_host() + ws_path = WS_PUBLIC_PATH if WS_PUBLIC_PATH else '/' if ':' in ws_host: ws_host = re.sub(':[0-9]+', '', ws_host) diff --git a/instances/templates/compute_instances.html b/instances/templates/compute_instances.html new file mode 100644 index 0000000..e96c763 --- /dev/null +++ b/instances/templates/compute_instances.html @@ -0,0 +1,199 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "Instances" %} - {{ compute.name }}{% 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">{{ compute.name }}</h1> + </div> + </div> + <div class="row"> + <div class="col-lg-12"> + + <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 --> + + {% include 'errors_block.html' %} + <div class="row"> + {% 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 "Hypervisor doesn't have any instances" %} + </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> +<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 = "/instance/" + compute + "/" + instance + "/#clone"; + } +</script> +{% if request.user.is_superuser %} + <script> + function goto_compute() { + var compute = $("#compute_select").val(); + window.location = "/compute/" + compute + "/create/"; + } + </script> +{% endif %} +{% endblock %} diff --git a/instances/templates/instances_grouped.html b/instances/templates/instances_grouped.html index 2e129c2..0d16056 100644 --- a/instances/templates/instances_grouped.html +++ b/instances/templates/instances_grouped.html @@ -15,6 +15,7 @@ {% for host, inst in all_host_vms.items %} <tr class="active" style="font-weight: bold;border-bottom: 2px solid darkgray;border-top: 2px solid darkgray;"> <td> + <span style="text-align:center;">{{ inst.items|length }}</span> <span id="collapse_host_instances_{{ host.1 }}" class="glyphicon glyphicon-chevron-up" onclick="hide_host_instances('{{ host.1 }}');"></span> </td> <td><a href="{% url 'overview' host.0 %}">{{ host.1 }}</a></td> diff --git a/instances/views.py b/instances/views.py index 70fb9bf..19db3fb 100644 --- a/instances/views.py +++ b/instances/views.py @@ -38,7 +38,7 @@ def index(request): @login_required -def instances(request): +def instances(request, compute_id=None): """ :param request: :return: @@ -47,7 +47,11 @@ def instances(request): error_messages = [] all_host_vms = {} all_user_vms = {} - computes = Compute.objects.all().order_by("name") + + if not compute_id: + computes = Compute.objects.all().order_by("name") + else: + computes = [Compute.objects.get(id=compute_id),] def get_userinstances_info(instance): info = {} @@ -195,8 +199,11 @@ def instances(request): view_style = settings.VIEW_INSTANCES_LIST_STYLE - return render(request, 'instances.html', locals()) + if compute_id: + compute = computes[0] + return render(request, 'compute_instances.html', locals()) + return render(request, 'instances.html', locals()) @login_required def instance(request, compute_id, vname): diff --git a/interfaces/templates/interfaces.html b/interfaces/templates/interfaces.html index 58d4978..c121595 100644 --- a/interfaces/templates/interfaces.html +++ b/interfaces/templates/interfaces.html @@ -12,6 +12,9 @@ <li class="active"> <i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a> </li> + <li class="active"> + <i class="fa fa-server"></i> <a href="{% url 'compute_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> @@ -94,4 +97,4 @@ }).change(); }); </script> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/networks/templates/networks.html b/networks/templates/networks.html index 2acc1f3..5e843ae 100644 --- a/networks/templates/networks.html +++ b/networks/templates/networks.html @@ -11,6 +11,9 @@ <li class="active"> <i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a> </li> + <li class="active"> + <i class="fa fa-server"></i> <a href="{% url 'compute_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> @@ -80,4 +83,4 @@ }).change(); }); </script> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/nwfilters/templates/nwfilters.html b/nwfilters/templates/nwfilters.html index e237380..9fd228f 100644 --- a/nwfilters/templates/nwfilters.html +++ b/nwfilters/templates/nwfilters.html @@ -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 'compute_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> diff --git a/secrets/templates/secrets.html b/secrets/templates/secrets.html index 07b104a..28d8dbd 100644 --- a/secrets/templates/secrets.html +++ b/secrets/templates/secrets.html @@ -10,11 +10,14 @@ <div class="row"> <div class="col-lg-12"> {% include 'create_secret_block.html' %} - <h1 class="page-header">{% trans "Secrets" %}</h1> + <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 class="active"> + <i class="fa fa-server"></i> <a href="{% url 'compute_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> @@ -122,4 +125,4 @@ {% endblock %} {% block script %} <script src="{% static "js/sortable.min.js" %}"></script> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/static/js/sortable.min.js b/static/js/sortable.min.js index 8278f50..b88c451 100755 --- a/static/js/sortable.min.js +++ b/static/js/sortable.min.js @@ -1,2 +1,2 @@ /*! sortable.js 0.8.0 */ -(function(){var a,b,c,d,e,f,g;a="table[data-sortable]",d=/^-?[£$¤]?[\d,.]+%?$/,g=/^\s+|\s+$/g,c=["click"],f="ontouchstart"in document.documentElement,f&&c.push("touchstart"),b=function(a,b,c){return null!=a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},e={init:function(b){var c,d,f,g,h;for(null==b&&(b={}),null==b.selector&&(b.selector=a),d=document.querySelectorAll(b.selector),h=[],f=0,g=d.length;g>f;f++)c=d[f],h.push(e.initTable(c));return h},initTable:function(a){var b,c,d,f,g,h;if(1===(null!=(h=a.tHead)?h.rows.length:void 0)&&"true"!==a.getAttribute("data-sortable-initialized")){for(a.setAttribute("data-sortable-initialized","true"),d=a.querySelectorAll("th"),b=f=0,g=d.length;g>f;b=++f)c=d[b],"false"!==c.getAttribute("data-sortable")&&e.setupClickableTH(a,c,b);return a}},setupClickableTH:function(a,d,f){var g,h,i,j,k,l;for(i=e.getColumnType(a,f),h=function(b){var c,g,h,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D;if(b.handled===!0)return!1;for(b.handled=!0,m="true"===this.getAttribute("data-sorted"),n=this.getAttribute("data-sorted-direction"),h=m?"ascending"===n?"descending":"ascending":i.defaultSortDirection,p=this.parentNode.querySelectorAll("th"),s=0,w=p.length;w>s;s++)d=p[s],d.setAttribute("data-sorted","false"),d.removeAttribute("data-sorted-direction");if(this.setAttribute("data-sorted","true"),this.setAttribute("data-sorted-direction",h),o=a.tBodies[0],l=[],m){for(D=o.rows,v=0,z=D.length;z>v;v++)g=D[v],l.push(g);for(l.reverse(),B=0,A=l.length;A>B;B++)k=l[B],o.appendChild(k)}else{for(r=null!=i.compare?i.compare:function(a,b){return b-a},c=function(a,b){return a[0]===b[0]?a[2]-b[2]:i.reverse?r(b[0],a[0]):r(a[0],b[0])},C=o.rows,j=t=0,x=C.length;x>t;j=++t)k=C[j],q=e.getNodeValue(k.cells[f]),null!=i.comparator&&(q=i.comparator(q)),l.push([q,k,j]);for(l.sort(c),u=0,y=l.length;y>u;u++)k=l[u],o.appendChild(k[1])}return"function"==typeof window.CustomEvent&&"function"==typeof a.dispatchEvent?a.dispatchEvent(new CustomEvent("Sortable.sorted",{bubbles:!0})):void 0},l=[],j=0,k=c.length;k>j;j++)g=c[j],l.push(b(d,g,h));return l},getColumnType:function(a,b){var c,d,f,g,h,i,j,k,l,m,n;if(d=null!=(l=a.querySelectorAll("th")[b])?l.getAttribute("data-sortable-type"):void 0,null!=d)return e.typesObject[d];for(m=a.tBodies[0].rows,h=0,j=m.length;j>h;h++)for(c=m[h],f=e.getNodeValue(c.cells[b]),n=e.types,i=0,k=n.length;k>i;i++)if(g=n[i],g.match(f))return g;return e.typesObject.alpha},getNodeValue:function(a){var b;return a?(b=a.getAttribute("data-value"),null!==b?b:"undefined"!=typeof a.innerText?a.innerText.replace(g,""):a.textContent.replace(g,"")):""},setupTypes:function(a){var b,c,d,f;for(e.types=a,e.typesObject={},f=[],c=0,d=a.length;d>c;c++)b=a[c],f.push(e.typesObject[b.name]=b);return f}},e.setupTypes([{name:"numeric",defaultSortDirection:"descending",match:function(a){return a.match(d)},comparator:function(a){return parseFloat(a.replace(/[^0-9.-]/g,""),10)||0}},{name:"date",defaultSortDirection:"ascending",reverse:!0,match:function(a){return!isNaN(Date.parse(a))},comparator:function(a){return Date.parse(a)||0}},{name:"alpha",defaultSortDirection:"ascending",match:function(){return!0},compare:function(a,b){return a.localeCompare(b)}}]),setTimeout(e.init,0),"function"==typeof define&&define.amd?define(function(){return e}):"undefined"!=typeof exports?module.exports=e:window.Sortable=e}).call(this); \ No newline at end of file +(function(){var a,b,c,d,e,f,g;a="table[data-sortable]",d=/^-?[£$¤]?[\d,.]+%?$/,g=/^\s+|\s+$/g,c=["click"],f="ontouchstart"in document.documentElement,f&&c.push("touchstart"),b=function(a,b,c){return null!=a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent("on"+b,c)},e={init:function(b){var c,d,f,g,h;for(null==b&&(b={}),null==b.selector&&(b.selector=a),d=document.querySelectorAll(b.selector),h=[],f=0,g=d.length;g>f;f++)c=d[f],h.push(e.initTable(c));return h},initTable:function(a){var b,c,d,f,g,h;if(1===(null!=(h=a.tHead)?h.rows.length:void 0)&&"true"!==a.getAttribute("data-sortable-initialized")){for(a.setAttribute("data-sortable-initialized","true"),d=a.querySelectorAll("th"),b=f=0,g=d.length;g>f;b=++f)c=d[b],"false"!==c.getAttribute("data-sortable")&&e.setupClickableTH(a,c,b);return a}},setupClickableTH:function(a,d,f){var g,h,i,j,k,l;for(i=e.getColumnType(a,f),h=function(b){var c,g,h,j,k,l,m,n,o,p,q,r,s,t,u,v,w,x,y,z,A,B,C,D;if(b.handled===!0)return!1;for(b.handled=!0,m="true"===this.getAttribute("data-sorted"),n=this.getAttribute("data-sorted-direction"),h=m?"ascending"===n?"descending":"ascending":i.defaultSortDirection,p=this.parentNode.querySelectorAll("th"),s=0,w=p.length;w>s;s++)d=p[s],d.setAttribute("data-sorted","false"),d.removeAttribute("data-sorted-direction");if(this.setAttribute("data-sorted","true"),this.setAttribute("data-sorted-direction",h),o=a.tBodies[0],l=[],m){for(D=o.rows,v=0,z=D.length;z>v;v++)g=D[v],l.push(g);for(l.reverse(),B=0,A=l.length;A>B;B++)k=l[B],o.appendChild(k)}else{for(r=null!=i.compare?i.compare:function(a,b){return b-a},c=function(a,b){return a[0]===b[0]?a[2]-b[2]:i.reverse?r(b[0],a[0]):r(a[0],b[0])},C=o.rows,j=t=0,x=C.length;x>t;j=++t)k=C[j],q=e.getNodeValue(k.cells[f]),null!=i.comparator&&(q=i.comparator(q)),l.push([q,k,j]);for(l.sort(c),u=0,y=l.length;y>u;u++)k=l[u],o.appendChild(k[1])}return"function"==typeof window.CustomEvent&&"function"==typeof a.dispatchEvent?a.dispatchEvent(new CustomEvent("Sortable.sorted",{bubbles:!0})):void 0},l=[],j=0,k=c.length;k>j;j++)g=c[j],l.push(b(d,g,h));return l},getColumnType:function(a,b){var c,d,f,g,h,i,j,k,l,m,n;if(d=null!=(l=a.querySelectorAll("th")[b])?l.getAttribute("data-sortable-type"):void 0,null!=d)return e.typesObject[d];for(m=a.tBodies[0].rows,h=0,j=m.length;j>h;h++)for(c=m[h],f=e.getNodeValue(c.cells[b]),n=e.types,i=0,k=n.length;k>i;i++)if(g=n[i],g.match(f))return g;return e.typesObject.alpha},getNodeValue:function(a){var b;return a?(b=a.getAttribute("data-value"),null!==b?b:"undefined"!=typeof a.innerText?a.innerText.replace(g,""):a.textContent.replace(g,"")):""},setupTypes:function(a){var b,c,d,f;for(e.types=a,e.typesObject={},f=[],c=0,d=a.length;d>c;c++)b=a[c],f.push(e.typesObject[b.name]=b);return f}},e.setupTypes([{name:"numeric",defaultSortDirection:"descending",match:function(a){return a.match(d)},comparator:function(a){return parseFloat(a.replace(/[^0-9.-]/g,""),10)||0}},{name:"date",defaultSortDirection:"ascending",reverse:!0,match:function(a){return!isNaN(Date.parse(a))},comparator:function(a){return Date.parse(a)||0}},{name:"alpha",defaultSortDirection:"ascending",match:function(){return!0},compare:function(a,b){return a.localeCompare(b)}}]),setTimeout(e.init,0),"function"==typeof define&&define.amd?define(function(){return e}):"undefined"!=typeof exports?module.exports=e:window.Sortable=e}).call(this); diff --git a/storages/templates/storage.html b/storages/templates/storage.html index 4d3c706..77e45e0 100644 --- a/storages/templates/storage.html +++ b/storages/templates/storage.html @@ -45,7 +45,7 @@ <p>{% trans "Pool type:" %}</p> <p>{% trans "Pool path:" %}</p> <p>{% trans "Pool status:" %}</p> - <p>{% trans "Size:" %} ({{ size|filesizeformat }} / {{ used|filesizeformat }})</p> + <p>{% trans "Size:" %} (Used: {{ used|filesizeformat }} / From total: {{ size|filesizeformat }})</p> <p>{% trans "State:" %}</p> <p>{% trans "Autostart:" %}</p> </div> diff --git a/storages/templates/storages.html b/storages/templates/storages.html index 026fe13..20f147c 100644 --- a/storages/templates/storages.html +++ b/storages/templates/storages.html @@ -11,6 +11,9 @@ <li class="active"> <i class="fa fa-dashboard"></i> <a href="{% url 'overview' compute.id %}">{% trans "Overview" %}</a> </li> + <li class="active"> + <i class="fa fa-server"></i> <a href="{% url 'compute_instances' compute.id %}">{% trans "Instances" %}</a> + </li> <li> <i class="fa fa-hdd-o"></i> {% trans "Storages" %} </li> @@ -67,4 +70,4 @@ {% endfor %} {% endif %} </div> -{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py index 79992af..2aa2c58 100644 --- a/webvirtcloud/urls.py +++ b/webvirtcloud/urls.py @@ -8,6 +8,7 @@ from create.views import create_instance from interfaces.views import interfaces, interface from console.views import console from nwfilters.views import nwfilters, nwfilter +from computes.views import computes # from django.contrib import admin urlpatterns = [ @@ -15,8 +16,13 @@ urlpatterns = [ url(r'^instances/$', instances, name='instances'), url(r'^instance/', include('instances.urls')), + url(r'^instances/$', instances, name='instances'), + url(r'^accounts/', include('accounts.urls')), + url(r'^computes/', include('computes.urls')), + url(r'^computes/', computes, name='computes'), + url(r'^logs/', include('logs.urls')), url(r'^datasource/', include('datasource.urls')),