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..0d2e2f1 --- /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..99686ed --- /dev/null +++ b/nwfilters/views.py @@ -0,0 +1,211 @@ +# -*- coding: utf-8 -*- +from __future__ import unicode_literals + +from django.shortcuts import render +from django.http import HttpResponseRedirect +from django.shortcuts import render, get_object_or_404 +from django.utils.translation import ugettext_lazy as _ +from django.core.urlresolvers import reverse +from django.contrib.auth.decorators import login_required +from computes.models import Compute +from vrtManager import util +from vrtManager.nwfilters import wvmNWFilters, wvmNWFilter +from vrtManager.instance import wvmInstances, wvmInstance +from libvirt import libvirtError +from logs.views import addlogmsg + + +@login_required +def nwfilters(request, compute_id): + """ + :param request: + :return: + """ + + if not request.user.is_superuser: + return HttpResponseRedirect(reverse('index')) + + error_messages = [] + nwfilters_all = [] + compute = get_object_or_404(Compute, pk=compute_id) + + try: + conn = wvmNWFilters(compute.hostname, + compute.login, + compute.password, + compute.type) + + if request.method == 'POST': + if 'create_nwfilter' in request.POST: + xml = request.POST.get('nwfilter_xml', '') + if xml: + try: + util.etree.fromstring(xml) + name = util.get_xml_path(xml, '/filter/@name') + uuid = util.get_xml_path(xml, '/filter/uuid') + except util.etree.ParseError: + name = None + + for nwf in nwfilters: + if name == nwf.name(): + error_msg = _("A network filter with this name already exists") + raise Exception(error_msg) + if uuid == nwf.UUIDString(): + error_msg = _("A network filter with this uuid already exists") + raise Exception(error_msg) + else: + try: + msg = _("Creating NWFilter: %s" % name) + conn.create_nwfilter(xml) + addlogmsg(request.user.username, compute.hostname, msg) + except libvirtError as lib_err: + error_messages.append(lib_err.message) + addlogmsg(request.user.username, compute.hostname, lib_err.message) + + if 'del_nwfilter' in request.POST: + name = request.POST.get('nwfiltername','') + msg = _("Deleting NWFilter: %s" % name) + in_use = False + nwfilter = conn.get_nwfilter(name) + + is_conn = wvmInstances(compute.hostname, compute.login, compute.password, compute.type) + instances = is_conn.get_instances() + for inst in instances: + # if in_use: break + i_conn = wvmInstance(compute.hostname, compute.login, compute.password, compute.type, inst) + dom_filterrefs = i_conn.get_filterrefs() + + if name in dom_filterrefs: + in_use = True + msg = _("NWFilter is in use by %s. Cannot be deleted." % inst) + error_messages.append(msg) + addlogmsg(request.user.username, compute.hostname, msg) + i_conn.close() + break + + is_conn.close() + if nwfilter and not in_use: + nwfilter.undefine() + addlogmsg(request.user.username, compute.hostname, msg) + + if 'cln_nwfilter' in request.POST: + + name = request.POST.get('nwfiltername','') + cln_name = request.POST.get('cln_name', name + '-clone') + + conn.clone_nwfilter(name,cln_name) + msg = _("Cloning NWFilter %s as %s" % (name, cln_name)) + addlogmsg(request.user.username, compute.hostname, msg) + + for nwf in conn.get_nwfilters(): + nwfilters_all.append(conn.get_nwfilter_info(nwf.name())) + + conn.close() + except libvirtError as lib_err: + error_messages.append(lib_err) + addlogmsg(request.user.username, compute.hostname, lib_err) + except Exception as err: + error_messages.append(err) + addlogmsg(request.user.username, compute.hostname, err) + + return render(request, 'nwfilters.html', {'error_messages': error_messages, + 'nwfilters': nwfilters_all, + 'compute': compute}) + + +@login_required +def nwfilter(request, compute_id, nwfltr): + + error_messages = [] + nwfilters_all = [] + compute = get_object_or_404(Compute, pk=compute_id) + + try: + nwfilter = wvmNWFilter(compute.hostname, + compute.login, + compute.password, + compute.type, + nwfltr) + conn = wvmNWFilters(compute.hostname, + compute.login, + compute.password, + compute.type) + + for nwf in conn.get_nwfilters(): + nwfilters_all.append(conn.get_nwfilter_info(nwf.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..ca5568f 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -187,6 +187,19 @@ class wvmInstance(wvmConnect): title = util.get_xml_path(self._XMLDesc(0), "/domain/title") return title if title else '' + def get_filterrefs(self): + + def filterrefs(ctx): + result = [] + for net in ctx.xpath('/domain/devices/interface'): + filterref = net.xpath('filterref/@filter') + if filterref: + result.append(filterref[0]) + return result + + return util.get_xml_path(self._XMLDesc(0), func=filterrefs) + + def get_description(self): description = util.get_xml_path(self._XMLDesc(0), "/domain/description") return description if description else '' @@ -487,8 +500,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/settings.py.template b/webvirtcloud/settings.py.template index c75b1a2..72c5460 100644 --- a/webvirtcloud/settings.py.template +++ b/webvirtcloud/settings.py.template @@ -24,6 +24,7 @@ INSTALLED_APPS = ( 'networks', 'storages', 'interfaces', + 'nwfilters', 'instances', 'secrets', 'logs', 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)), ]