From 3f1acf09ef3f29d8c0cfa565d0cd069d890cfa65 Mon Sep 17 00:00:00 2001 From: catborise Date: Fri, 21 Sep 2018 16:50:44 +0300 Subject: [PATCH 01/18] Add NWFilters --- computes/templates/overview.html | 3 + interfaces/templates/interface.html | 3 + interfaces/templates/interfaces.html | 3 + networks/templates/network.html | 3 + networks/templates/networks.html | 3 + nwfilters/__init__.py | 0 nwfilters/admin.py | 6 + nwfilters/apps.py | 8 + nwfilters/migrations/__init__.py | 0 nwfilters/models.py | 6 + .../templates/create_nwfilter_block.html | 32 +++ nwfilters/templates/nwfilter.html | 220 ++++++++++++++++++ nwfilters/templates/nwfilters.html | 168 +++++++++++++ nwfilters/tests.py | 6 + nwfilters/views.py | 183 +++++++++++++++ secrets/templates/secrets.html | 3 + storages/templates/storage.html | 3 + storages/templates/storages.html | 3 + vrtManager/connection.py | 10 +- vrtManager/instance.py | 3 +- vrtManager/nwfilters.py | 125 ++++++++++ webvirtcloud/urls.py | 4 + 22 files changed, 792 insertions(+), 3 deletions(-) create mode 100644 nwfilters/__init__.py create mode 100644 nwfilters/admin.py create mode 100644 nwfilters/apps.py create mode 100644 nwfilters/migrations/__init__.py create mode 100644 nwfilters/models.py create mode 100644 nwfilters/templates/create_nwfilter_block.html create mode 100644 nwfilters/templates/nwfilter.html create mode 100644 nwfilters/templates/nwfilters.html create mode 100644 nwfilters/tests.py create mode 100644 nwfilters/views.py create mode 100644 vrtManager/nwfilters.py diff --git a/computes/templates/overview.html b/computes/templates/overview.html index 34e68c5..89251cc 100644 --- a/computes/templates/overview.html +++ b/computes/templates/overview.html @@ -20,6 +20,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/interfaces/templates/interface.html b/interfaces/templates/interface.html index c55750d..014a44e 100644 --- a/interfaces/templates/interface.html +++ b/interfaces/templates/interface.html @@ -19,6 +19,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/interfaces/templates/interfaces.html b/interfaces/templates/interfaces.html index 42d4456..58d4978 100644 --- a/interfaces/templates/interfaces.html +++ b/interfaces/templates/interfaces.html @@ -21,6 +21,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/networks/templates/network.html b/networks/templates/network.html index 7d922b1..e3b0275 100644 --- a/networks/templates/network.html +++ b/networks/templates/network.html @@ -19,6 +19,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/networks/templates/networks.html b/networks/templates/networks.html index 36322e2..2acc1f3 100644 --- a/networks/templates/networks.html +++ b/networks/templates/networks.html @@ -20,6 +20,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/nwfilters/__init__.py b/nwfilters/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nwfilters/admin.py b/nwfilters/admin.py new file mode 100644 index 0000000..13be29d --- /dev/null +++ b/nwfilters/admin.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.contrib import admin + +# Register your models here. diff --git a/nwfilters/apps.py b/nwfilters/apps.py new file mode 100644 index 0000000..11475c5 --- /dev/null +++ b/nwfilters/apps.py @@ -0,0 +1,8 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.apps import AppConfig + + +class NwfiltersConfig(AppConfig): + name = 'nwfilters' diff --git a/nwfilters/migrations/__init__.py b/nwfilters/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/nwfilters/models.py b/nwfilters/models.py new file mode 100644 index 0000000..1dfab76 --- /dev/null +++ b/nwfilters/models.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.db import models + +# Create your models here. diff --git a/nwfilters/templates/create_nwfilter_block.html b/nwfilters/templates/create_nwfilter_block.html new file mode 100644 index 0000000..01056ab --- /dev/null +++ b/nwfilters/templates/create_nwfilter_block.html @@ -0,0 +1,32 @@ +{% load i18n %} +{% if request.user.is_superuser %} + + + + + + +{% endif %} diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html new file mode 100644 index 0000000..1f7c7b0 --- /dev/null +++ b/nwfilters/templates/nwfilter.html @@ -0,0 +1,220 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %} +{% block content %} + +
    +
    + {% include 'create_nwfilter_block.html' %} +

    {% trans "NWFilter:" %} {{ name }}

    + +
    +
    + + + {% include 'errors_block.html' %} + {% include 'messages_block.html' %} + +
    +
    +

    {% trans "UUID:" %}

    +

    {% trans "Name:" %}

    +
    + +
    +

    {{ uuid }}

    +

    {{ name }}

    +
    + +
    +
    +

    {% trans "XML:" %}

    +
    {% csrf_token %} +
    + + +
    + +
    +
    +
    +

    {% trans "Filter References:" %}

    +
    {% csrf_token %} +
    + + + + +
    +
    + +
    +
    +
    + + + + + + + + + + {% for ref in refs %} + + + + + + {% endfor %} + +
    #{% trans "Reference" %}{% trans "Action" %}
    {{ forloop.counter }}{{ ref }} +
    {% csrf_token %} + + +
    +
    +
    +
    +
    +

    {% trans "Rules:" %}

    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + {% for rule in rules %} + + + + + + + + + + {% endfor %} + +
    {% trans "Rule" %}{% trans "ActionType" %}{% trans "Direction" %}{% trans "Priority" %}{% trans "Statematch" %}{% trans "Directives" %}{% trans "Action" %}
    {{ forloop.counter }}{{ rule.action }}{{ rule.direction }}{{ rule.priority }}{{ rule.statematch }}{{ rule.directives }} +
    {% csrf_token %} + + + + +
    +
    +
    +
    + + +{% endblock %} + +{% block script %} + + + + + +{% endblock %} diff --git a/nwfilters/templates/nwfilters.html b/nwfilters/templates/nwfilters.html new file mode 100644 index 0000000..e237380 --- /dev/null +++ b/nwfilters/templates/nwfilters.html @@ -0,0 +1,168 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %} +{% block content %} + +
    +
    + {% include 'create_nwfilter_block.html' %} +

    {{ compute.name }}

    + +
    +
    + + +{% include 'errors_block.html' %} +{% include 'messages_block.html' %} + +
    +
    +
    +
    + +
    + + +
    + {% if nwfilters %} +
    + + + + + + + + + + + {% for nwfilter in nwfilters %} + + + + + + + + + {% endfor %} + +
    #{% trans "UUID" %}{% trans "Name" %}{% trans "Action" %}
    {{ forloop.counter }}{{ nwfilter.uuid }}{{ nwfilter.name }} + + + + + + +
    {% csrf_token %} + + +
    +
    +
    + {% else %} +
    +
    + + {% trans "Warning:" %} {% trans "Hypervisor doesn't have any NWFilters" %} +
    +
    + {% endif %} +
    +
    +{% endblock %} + +{% block script %} + + + + + + + +{% endblock %} diff --git a/nwfilters/tests.py b/nwfilters/tests.py new file mode 100644 index 0000000..5982e6b --- /dev/null +++ b/nwfilters/tests.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.test import TestCase + +# Create your tests here. diff --git a/nwfilters/views.py b/nwfilters/views.py new file mode 100644 index 0000000..5fa39f5 --- /dev/null +++ b/nwfilters/views.py @@ -0,0 +1,183 @@ +# -*- 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 libvirt import libvirtError + + +@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) + + for nwf in conn.get_nwfilters(): + nwfilters_all.append(conn.get_nwfilter_info(nwf.name())) + + 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: + conn.create_nwfilter(xml) + return HttpResponseRedirect(request.get_full_path()) + except libvirtError as lib_err: + error_messages.append(lib_err.message) + if 'del_nwfilter' in request.POST: + name = request.POST.get('nwfiltername','') + nwfilter = conn.get_nwfilter(name) + if nwfilter: + nwfilter.undefine() + return HttpResponseRedirect(request.get_full_path()) + + 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) + return HttpResponseRedirect(request.get_full_path()) + + conn.close() + except libvirtError as lib_err: + error_messages.append(lib_err) + except Exception as err: + error_messages.append(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.name())) + + 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()) \ No newline at end of file diff --git a/secrets/templates/secrets.html b/secrets/templates/secrets.html index 8286bfb..07b104a 100644 --- a/secrets/templates/secrets.html +++ b/secrets/templates/secrets.html @@ -24,6 +24,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/storages/templates/storage.html b/storages/templates/storage.html index ecc9adc..4d3c706 100644 --- a/storages/templates/storage.html +++ b/storages/templates/storage.html @@ -25,6 +25,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/storages/templates/storages.html b/storages/templates/storages.html index 21bca90..026fe13 100644 --- a/storages/templates/storages.html +++ b/storages/templates/storages.html @@ -20,6 +20,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/vrtManager/connection.py b/vrtManager/connection.py index 65c2915..96a4fbf 100644 --- a/vrtManager/connection.py +++ b/vrtManager/connection.py @@ -389,6 +389,12 @@ class wvmConnect(object): interface.append(inface) return interface + def get_nwfilters(self): + nwfilters = [] + for nwfilter in self.wvm.listAllNWFilters(): + 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) diff --git a/vrtManager/instance.py b/vrtManager/instance.py index b27baa0..d63d36c 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -487,8 +487,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): diff --git a/vrtManager/nwfilters.py b/vrtManager/nwfilters.py new file mode 100644 index 0000000..58784b9 --- /dev/null +++ b/vrtManager/nwfilters.py @@ -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) diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py index d169386..79992af 100644 --- a/webvirtcloud/urls.py +++ b/webvirtcloud/urls.py @@ -7,6 +7,7 @@ from secrets.views import secrets from create.views import create_instance from interfaces.views import interfaces, interface from console.views import console +from nwfilters.views import nwfilters, nwfilter # from django.contrib import admin urlpatterns = [ @@ -25,9 +26,12 @@ urlpatterns = [ url(r'^compute/(?P[0-9]+)/network/(?P[\w\-\.]+)/$', network, name='network'), url(r'^compute/(?P[0-9]+)/interfaces/$', interfaces, name='interfaces'), url(r'^compute/(?P[0-9]+)/interface/(?P[\w\-\.\:]+)/$', interface, name='interface'), + url(r'^compute/(?P[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'), + url(r'^compute/(?P[0-9]+)/nwfilter/(?P[\w\-\.\:]+)/$', nwfilter, name='nwfilter'), url(r'^compute/(?P[0-9]+)/secrets/$', secrets, name='secrets'), url(r'^compute/(?P[0-9]+)/create/$', create_instance, name='create_instance'), + url(r'^console/$', console, name='console'), # (r'^admin/', include(admin.site.urls)), ] From 1802ad0413df2a009ba7bd23c78223fa726bcdd8 Mon Sep 17 00:00:00 2001 From: catborise Date: Fri, 21 Sep 2018 18:46:33 +0300 Subject: [PATCH 02/18] Check usage of filter refs from domains. --- nwfilters/templates/nwfilter.html | 2 +- nwfilters/views.py | 42 +++++++++++++++++++++++++------ vrtManager/instance.py | 13 ++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html index 1f7c7b0..0d2e2f1 100644 --- a/nwfilters/templates/nwfilter.html +++ b/nwfilters/templates/nwfilter.html @@ -65,7 +65,7 @@
    + +
    + + + + + + + +{% endif %} diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html new file mode 100644 index 0000000..1f7c7b0 --- /dev/null +++ b/nwfilters/templates/nwfilter.html @@ -0,0 +1,220 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %} +{% block content %} + +
    +
    + {% include 'create_nwfilter_block.html' %} +

    {% trans "NWFilter:" %} {{ name }}

    + +
    +
    + + + {% include 'errors_block.html' %} + {% include 'messages_block.html' %} + +
    +
    +

    {% trans "UUID:" %}

    +

    {% trans "Name:" %}

    +
    + +
    +

    {{ uuid }}

    +

    {{ name }}

    +
    + +
    +
    +

    {% trans "XML:" %}

    +
    {% csrf_token %} +
    + + +
    + +
    +
    +
    +

    {% trans "Filter References:" %}

    +
    {% csrf_token %} +
    + + + + +
    +
    + +
    +
    +
    + + + + + + + + + + {% for ref in refs %} + + + + + + {% endfor %} + +
    #{% trans "Reference" %}{% trans "Action" %}
    {{ forloop.counter }}{{ ref }} +
    {% csrf_token %} + + +
    +
    +
    +
    +
    +

    {% trans "Rules:" %}

    + + + + + + +
    +
    +
    + + + + + + + + + + + + + + {% for rule in rules %} + + + + + + + + + + {% endfor %} + +
    {% trans "Rule" %}{% trans "ActionType" %}{% trans "Direction" %}{% trans "Priority" %}{% trans "Statematch" %}{% trans "Directives" %}{% trans "Action" %}
    {{ forloop.counter }}{{ rule.action }}{{ rule.direction }}{{ rule.priority }}{{ rule.statematch }}{{ rule.directives }} +
    {% csrf_token %} + + + + +
    +
    +
    +
    + + +{% endblock %} + +{% block script %} + + + + + +{% endblock %} diff --git a/nwfilters/templates/nwfilters.html b/nwfilters/templates/nwfilters.html new file mode 100644 index 0000000..e237380 --- /dev/null +++ b/nwfilters/templates/nwfilters.html @@ -0,0 +1,168 @@ +{% extends "base.html" %} +{% load i18n %} +{% load staticfiles %} +{% block title %}{% trans "NWFilters" %} - {{ compute.name }}{% endblock %} +{% block content %} + +
    +
    + {% include 'create_nwfilter_block.html' %} +

    {{ compute.name }}

    + +
    +
    + + +{% include 'errors_block.html' %} +{% include 'messages_block.html' %} + +
    +
    +
    +
    + +
    + + +
    + {% if nwfilters %} +
    + + + + + + + + + + + {% for nwfilter in nwfilters %} + + + + + + + + + {% endfor %} + +
    #{% trans "UUID" %}{% trans "Name" %}{% trans "Action" %}
    {{ forloop.counter }}{{ nwfilter.uuid }}{{ nwfilter.name }} + + + + + + +
    {% csrf_token %} + + +
    +
    +
    + {% else %} +
    +
    + + {% trans "Warning:" %} {% trans "Hypervisor doesn't have any NWFilters" %} +
    +
    + {% endif %} +
    +
    +{% endblock %} + +{% block script %} + + + + + + + +{% endblock %} diff --git a/nwfilters/tests.py b/nwfilters/tests.py new file mode 100644 index 0000000..5982e6b --- /dev/null +++ b/nwfilters/tests.py @@ -0,0 +1,6 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.test import TestCase + +# Create your tests here. diff --git a/nwfilters/views.py b/nwfilters/views.py new file mode 100644 index 0000000..5fa39f5 --- /dev/null +++ b/nwfilters/views.py @@ -0,0 +1,183 @@ +# -*- 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 libvirt import libvirtError + + +@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) + + for nwf in conn.get_nwfilters(): + nwfilters_all.append(conn.get_nwfilter_info(nwf.name())) + + 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: + conn.create_nwfilter(xml) + return HttpResponseRedirect(request.get_full_path()) + except libvirtError as lib_err: + error_messages.append(lib_err.message) + if 'del_nwfilter' in request.POST: + name = request.POST.get('nwfiltername','') + nwfilter = conn.get_nwfilter(name) + if nwfilter: + nwfilter.undefine() + return HttpResponseRedirect(request.get_full_path()) + + 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) + return HttpResponseRedirect(request.get_full_path()) + + conn.close() + except libvirtError as lib_err: + error_messages.append(lib_err) + except Exception as err: + error_messages.append(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.name())) + + 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()) \ No newline at end of file diff --git a/secrets/templates/secrets.html b/secrets/templates/secrets.html index 8286bfb..07b104a 100644 --- a/secrets/templates/secrets.html +++ b/secrets/templates/secrets.html @@ -24,6 +24,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/storages/templates/storage.html b/storages/templates/storage.html index ecc9adc..4d3c706 100644 --- a/storages/templates/storage.html +++ b/storages/templates/storage.html @@ -25,6 +25,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/storages/templates/storages.html b/storages/templates/storages.html index 21bca90..026fe13 100644 --- a/storages/templates/storages.html +++ b/storages/templates/storages.html @@ -20,6 +20,9 @@
  • {% trans "Interfaces" %}
  • +
  • + {% trans "NWFilters" %} +
  • {% trans "Secrets" %}
  • diff --git a/vrtManager/connection.py b/vrtManager/connection.py index 65c2915..96a4fbf 100644 --- a/vrtManager/connection.py +++ b/vrtManager/connection.py @@ -389,6 +389,12 @@ class wvmConnect(object): interface.append(inface) return interface + def get_nwfilters(self): + nwfilters = [] + for nwfilter in self.wvm.listAllNWFilters(): + 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) diff --git a/vrtManager/instance.py b/vrtManager/instance.py index b27baa0..d63d36c 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -487,8 +487,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): diff --git a/vrtManager/nwfilters.py b/vrtManager/nwfilters.py new file mode 100644 index 0000000..58784b9 --- /dev/null +++ b/vrtManager/nwfilters.py @@ -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) diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py index d169386..79992af 100644 --- a/webvirtcloud/urls.py +++ b/webvirtcloud/urls.py @@ -7,6 +7,7 @@ from secrets.views import secrets from create.views import create_instance from interfaces.views import interfaces, interface from console.views import console +from nwfilters.views import nwfilters, nwfilter # from django.contrib import admin urlpatterns = [ @@ -25,9 +26,12 @@ urlpatterns = [ url(r'^compute/(?P[0-9]+)/network/(?P[\w\-\.]+)/$', network, name='network'), url(r'^compute/(?P[0-9]+)/interfaces/$', interfaces, name='interfaces'), url(r'^compute/(?P[0-9]+)/interface/(?P[\w\-\.\:]+)/$', interface, name='interface'), + url(r'^compute/(?P[0-9]+)/nwfilters/$', nwfilters, name='nwfilters'), + url(r'^compute/(?P[0-9]+)/nwfilter/(?P[\w\-\.\:]+)/$', nwfilter, name='nwfilter'), url(r'^compute/(?P[0-9]+)/secrets/$', secrets, name='secrets'), url(r'^compute/(?P[0-9]+)/create/$', create_instance, name='create_instance'), + url(r'^console/$', console, name='console'), # (r'^admin/', include(admin.site.urls)), ] From 7f2104c19d30f331214943fdbaf34a7237064837 Mon Sep 17 00:00:00 2001 From: catborise Date: Fri, 21 Sep 2018 18:46:33 +0300 Subject: [PATCH 04/18] Check usage of filter refs from domains. --- nwfilters/templates/nwfilter.html | 2 +- nwfilters/views.py | 42 +++++++++++++++++++++++++------ vrtManager/instance.py | 13 ++++++++++ 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html index 1f7c7b0..0d2e2f1 100644 --- a/nwfilters/templates/nwfilter.html +++ b/nwfilters/templates/nwfilter.html @@ -65,7 +65,7 @@
    + +
    + +
    + +
    @@ -226,6 +237,17 @@
    +
    + +
    + +
    +
    @@ -379,6 +401,17 @@
    +
    + +
    + +
    +
    diff --git a/create/views.py b/create/views.py index 0c39a1d..9fb846e 100644 --- a/create/views.py +++ b/create/views.py @@ -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,7 +139,7 @@ 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() diff --git a/instances/templates/add_instance_network_block.html b/instances/templates/add_instance_network_block.html index 990c524..afb0ae5 100644 --- a/instances/templates/add_instance_network_block.html +++ b/instances/templates/add_instance_network_block.html @@ -33,12 +33,24 @@
    +
    + +
    + +
    + + diff --git a/instances/templates/instance.html b/instances/templates/instance.html index 9b34878..4dbfa6d 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -859,11 +859,8 @@ {% endfor %} - {% ifequal status 5 %} - - {% else %} - - {% endifequal %} + +
    diff --git a/instances/views.py b/instances/views.py index ec6adbc..0f4469f 100644 --- a/instances/views.py +++ b/instances/views.py @@ -364,6 +364,7 @@ def instance(request, compute_id, vname): else: media_iso = [] networks = conn.get_net_device() + nwfilters = conn.get_nwfilters() vcpu_range = conn.get_max_cpus() memory_range = [256, 512, 768, 1024, 2048, 4096, 6144, 8192, 16384] if memory not in memory_range: @@ -708,9 +709,10 @@ def instance(request, compute_id, vname): if 'add_network' in request.POST: mac = request.POST.get('add-net-mac') + nwfilter = request.POST.get('nwfilter') (source, source_type) = get_network_tuple(request.POST.get('add-net-network')) - conn.add_network(mac, source, source_type) + conn.add_network(mac, source, source_type, nwfilter=nwfilter) msg = _("Edit network") addlogmsg(request.user.username, instance.name, msg) msg = _("Network Devices are changed. Please reboot instance to activate.") diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html index 0d2e2f1..9f97831 100644 --- a/nwfilters/templates/nwfilter.html +++ b/nwfilters/templates/nwfilter.html @@ -22,7 +22,7 @@ {% trans "Interfaces" %}
  • - {% trans "NWFilters" %} + {% trans "NWFilters" %}
  • {% trans "Secrets" %} diff --git a/nwfilters/views.py b/nwfilters/views.py index 99686ed..c0dd8d8 100644 --- a/nwfilters/views.py +++ b/nwfilters/views.py @@ -98,7 +98,7 @@ def nwfilters(request, compute_id): addlogmsg(request.user.username, compute.hostname, msg) for nwf in conn.get_nwfilters(): - nwfilters_all.append(conn.get_nwfilter_info(nwf.name())) + nwfilters_all.append(conn.get_nwfilter_info(nwf)) conn.close() except libvirtError as lib_err: @@ -132,7 +132,7 @@ def nwfilter(request, compute_id, nwfltr): compute.type) for nwf in conn.get_nwfilters(): - nwfilters_all.append(conn.get_nwfilter_info(nwf.name())) + nwfilters_all.append(conn.get_nwfilter_info(nwf)) uuid = nwfilter.get_uuid() name = nwfilter.get_name() diff --git a/vrtManager/connection.py b/vrtManager/connection.py index 96a4fbf..1a16f4e 100644 --- a/vrtManager/connection.py +++ b/vrtManager/connection.py @@ -391,7 +391,7 @@ class wvmConnect(object): def get_nwfilters(self): nwfilters = [] - for nwfilter in self.wvm.listAllNWFilters(): + for nwfilter in self.wvm.listNWFilters(): nwfilters.append(nwfilter) return nwfilters diff --git a/vrtManager/instance.py b/vrtManager/instance.py index ca5568f..dd2db64 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -788,7 +788,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 = """ @@ -796,8 +796,13 @@ class wvmInstance(wvmConnect): - - """ % (interface_type, mac_address, bridge_name, model) + """ % (interface_type, mac_address, bridge_name, model) + if nwfilter: + xml_interface += """ + + """ % nwfilter + xml_interface += """""" + if self.get_status() == 5: devices = tree.find('devices') elm_interface = ElementTree.fromstring(xml_interface) From f7d2d24d0bca6bbe2fa649182f0cec0e47a75b8c Mon Sep 17 00:00:00 2001 From: catborise Date: Wed, 26 Sep 2018 16:19:32 +0300 Subject: [PATCH 07/18] message.success fix - (request was missing) --- storages/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/storages/views.py b/storages/views.py index f18cad6..71bee86 100644 --- a/storages/views.py +++ b/storages/views.py @@ -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) From 5d4a6009082bd6218f6a582838118be63cc5c0f5 Mon Sep 17 00:00:00 2001 From: catborise Date: Wed, 26 Sep 2018 17:16:48 +0300 Subject: [PATCH 08/18] success message converted to translate ready --- create/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/create/views.py b/create/views.py index 9fb846e..2cacdc4 100644 --- a/create/views.py +++ b/create/views.py @@ -143,7 +143,7 @@ def create_instance(request, compute_id): 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]: From ba212971faec023950169d14e197e24ad226029f Mon Sep 17 00:00:00 2001 From: catborise Date: Wed, 26 Sep 2018 17:18:30 +0300 Subject: [PATCH 09/18] success message converted to translate ready --- storages/views.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/storages/views.py b/storages/views.py index 71bee86..d2214aa 100644 --- a/storages/views.py +++ b/storages/views.py @@ -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(request, "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) From b916c9dcf916376209efdd66e971b465de94a286 Mon Sep 17 00:00:00 2001 From: catborise Date: Wed, 26 Sep 2018 17:20:46 +0300 Subject: [PATCH 10/18] instance network tab modified. Changing function modified. deleting function added. network info of nwfilters added. and some small fixes applied --- .../templates/add_instance_network_block.html | 4 +- instances/templates/instance.html | 75 ++++++++++++------- instances/views.py | 27 ++++--- vrtManager/instance.py | 27 ++++++- 4 files changed, 93 insertions(+), 40 deletions(-) diff --git a/instances/templates/add_instance_network_block.html b/instances/templates/add_instance_network_block.html index afb0ae5..9d65601 100644 --- a/instances/templates/add_instance_network_block.html +++ b/instances/templates/add_instance_network_block.html @@ -36,9 +36,9 @@
    - - {% for nwfilter in nwfilters %} + {% for nwfilter in compute_nwfilters %} {% endfor %} diff --git a/instances/templates/instance.html b/instances/templates/instance.html index 4dbfa6d..b61e73b 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -833,36 +833,63 @@ {% if request.user.is_superuser %}

    - {% trans "Assign network device to bridge" %} - {% include 'add_instance_network_block.html' %} + {% trans "Assign network device to bridge" %} + {% include 'add_instance_network_block.html' %}

    -
    {% csrf_token %} -

    {% trans "Network devices" %}

    +

    {% trans "Network devices" %}

    +
    + {% csrf_token %} {% for network in networks %} -
    - -
    - +
    +
    +
    -
    - +
    +
    + + + + +
    +
    + + + + +
    +
    + + + + +
    -
    - + +
    {% endfor %} - - + + + +
    +
    {% endif %} {% if request.user.is_superuser or request.user.userattributes.can_clone_instances %} @@ -1367,12 +1394,6 @@ }); }); - + + + +{% if request.user.is_superuser %} + +{% endif %} +{% endblock %} diff --git a/instances/templates/instances_grouped.html b/instances/templates/allinstances_index_grouped.html similarity index 100% rename from instances/templates/instances_grouped.html rename to instances/templates/allinstances_index_grouped.html diff --git a/instances/templates/instances_nongrouped.html b/instances/templates/allinstances_index_nongrouped.html similarity index 100% rename from instances/templates/instances_nongrouped.html rename to instances/templates/allinstances_index_nongrouped.html diff --git a/instances/templates/instances.html b/instances/templates/instances.html index 6750603..7edb9da 100644 --- a/instances/templates/instances.html +++ b/instances/templates/instances.html @@ -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 %} {% endblock %} {% block content %} - +
    {% if request.user.is_superuser %} @@ -17,129 +17,144 @@
    {% endif %} -

    {% trans "Instances" %}

    +

    {{ compute.name }}

    - +
    +
    - {% include 'errors_block.html' %} + +
    +
    + -
    + {% include 'errors_block.html' %} +
    + {% if not all_host_vms %}
    -
    - {% if request.user.is_superuser %} - {% if not all_host_vms %} -
    -
    - - {% trans "Warning:" %} {% trans "You don't have any Instance" %} -
    -
    - {% 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 %} -
    -
    - - {% trans "Warning:" %} {% trans "You don't have any Instance" %} -
    -
    - {% else %} - - - - - - - - - - - - {% for inst, vm in all_user_vms.items %} - - - - - - - - {% endfor %} - -
    NameStatusVCPUMemoryActions
    {{ vm.name }}
    {{ vm.title }}
    {% ifequal vm.status 1 %} - {% trans "Active" %} - {% endifequal %} - {% ifequal vm.status 5 %} - {% trans "Off" %} - {% endifequal %} - {% ifequal vm.status 3 %} - {% trans "Suspend" %} - {% endifequal %} - {{ vm.vcpu }}{{ vm.memory }} {% trans "MB" %}
    {% csrf_token %} - - - {% ifequal vm.status 5 %} - {% if inst.instance.is_template %} - - {% else %} - - {% endif %} - - - - {% endifequal %} - {% ifequal vm.status 3 %} - - - - - {% endifequal %} - {% ifequal vm.status 1 %} - - - - - - - {% endifequal %} -
    -
    - {% endif %} - {% endif %} +
    + + {% trans "Warning:" %} {% trans "Hypervisor doesn't have any instances" %}
    -
    + {% else %} +
    + + + + + + + + + + + + + {% for host, inst in all_host_vms.items %} + {% for vm, info in inst.items %} + + + + + + + + + {% endfor %} + {% endfor %} + +
    Name
    Description
    Host
    User
    StatusVCPUMemoryActions
    {{ vm }}
    {{ info.title }}
    {{ host.1 }}
    {% if info.userinstances.count > 0 %}{{ info.userinstances.first_user.user.username }}{% if info.userinstances.count > 1 %} (+{{ info.userinstances.count|add:"-1" }}){% endif %}{% endif %}
    + {% ifequal info.status 1 %}{% trans "Active" %}{% endifequal %} + {% ifequal info.status 5 %}{% trans "Off" %}{% endifequal %} + {% ifequal info.status 3 %}{% trans "Suspend" %}{% endifequal %} + {{ info.vcpu }}{{ info.memory|filesizeformat }}
    {% csrf_token %} + + + {% ifequal info.status 5 %} + {% if info.is_template %} + + {% else %} + + {% endif %} + + + + + {% endifequal %} + {% ifequal info.status 3 %} + + + + + + {% endifequal %} + {% ifequal info.status 1 %} + + + + + + + + {% endifequal %} +
    +
    +
    + {% endif %} +
    {% endblock %} {% block script %} @@ -181,4 +196,4 @@ } {% endif %} -{% endblock %} +{% endblock %} \ No newline at end of file diff --git a/instances/urls.py b/instances/urls.py index 93ac0c4..1054ed1 100644 --- a/instances/urls.py +++ b/instances/urls.py @@ -2,6 +2,7 @@ from django.conf.urls import url from . import views urlpatterns = [ + url(r'^$', views.allinstances, name='allinstances'), url(r'^(?P[0-9]+)/(?P[\w\-\.]+)/$', views.instance, name='instance'), url(r'^statistics/(?P[0-9]+)/(?P[\w\-\.]+)/$', views.inst_graph, name='inst_graph'), url(r'^status/(?P[0-9]+)/(?P[\w\-\.]+)/$', views.inst_status, name='inst_status'), diff --git a/instances/views.py b/instances/views.py index 70fb9bf..188b8e5 100644 --- a/instances/views.py +++ b/instances/views.py @@ -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: @@ -379,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() @@ -453,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 @@ -507,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', '') @@ -521,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: @@ -542,9 +441,9 @@ 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', default_format) @@ -553,7 +452,7 @@ def instance(request, compute_id, vname): 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, default_owner) conn.attach_disk(path, target, subdriver=format, cache=cache, targetbus=bus) msg = _('Attach new disk') @@ -670,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) @@ -705,7 +604,8 @@ def instance(request, compute_id, vname): conn.change_network(network_data) addlogmsg(request.user.username, instance.name, msg) - if conn.get_status() != 5: messages.success(request, _("Network Devices are changed. Please reboot instance to activate.")) + msg = _("Network Devices are changed. Please reboot instance to activate.") + if conn.get_status() != 5: messages.success(request, msg) return HttpResponseRedirect(request.get_full_path() + '#network') if 'add_network' in request.POST: @@ -717,7 +617,9 @@ def instance(request, compute_id, vname): conn.add_network(mac, source, source_type, nwfilter=nwfilter) addlogmsg(request.user.username, instance.name, msg) - if conn.get_status() != 5: messages.success(request, _("Network Device is added. Please reboot instance to activate.")) + 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: @@ -726,17 +628,18 @@ def instance(request, compute_id, vname): conn.delete_network(mac_address) addlogmsg(request.user.username, instance.name, msg) - if conn.get_status() != 5: messages.success(request, _("Network Device is deleted. Please reboot instance to activate.")) + 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) @@ -755,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 @@ -776,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) @@ -786,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) @@ -801,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') @@ -851,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): """ diff --git a/interfaces/templates/interface.html b/interfaces/templates/interface.html index 014a44e..5c5c2b5 100644 --- a/interfaces/templates/interface.html +++ b/interfaces/templates/interface.html @@ -10,6 +10,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/interfaces/templates/interfaces.html b/interfaces/templates/interfaces.html index 58d4978..8305b88 100644 --- a/interfaces/templates/interfaces.html +++ b/interfaces/templates/interfaces.html @@ -12,6 +12,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/networks/templates/network.html b/networks/templates/network.html index e3b0275..6fa0c2e 100644 --- a/networks/templates/network.html +++ b/networks/templates/network.html @@ -10,6 +10,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/networks/templates/networks.html b/networks/templates/networks.html index 2acc1f3..b57f7c6 100644 --- a/networks/templates/networks.html +++ b/networks/templates/networks.html @@ -11,6 +11,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/nwfilters/templates/nwfilter.html b/nwfilters/templates/nwfilter.html index 9f97831..377190d 100644 --- a/nwfilters/templates/nwfilter.html +++ b/nwfilters/templates/nwfilter.html @@ -12,6 +12,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/nwfilters/templates/nwfilters.html b/nwfilters/templates/nwfilters.html index e237380..dba8377 100644 --- a/nwfilters/templates/nwfilters.html +++ b/nwfilters/templates/nwfilters.html @@ -12,6 +12,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/secrets/templates/secrets.html b/secrets/templates/secrets.html index 07b104a..7f781ce 100644 --- a/secrets/templates/secrets.html +++ b/secrets/templates/secrets.html @@ -15,6 +15,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/storages/templates/storage.html b/storages/templates/storage.html index 4d3c706..17ed99c 100644 --- a/storages/templates/storage.html +++ b/storages/templates/storage.html @@ -16,6 +16,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/storages/templates/storages.html b/storages/templates/storages.html index 026fe13..7529842 100644 --- a/storages/templates/storages.html +++ b/storages/templates/storages.html @@ -11,6 +11,9 @@
  • {% trans "Overview" %}
  • +
  • + {% trans "Instances" %} +
  • {% trans "Storages" %}
  • diff --git a/templates/navbar.html b/templates/navbar.html index 6b69be4..1a1263b 100644 --- a/templates/navbar.html +++ b/templates/navbar.html @@ -15,7 +15,7 @@