From dd5f98cbe8d9d3d7883cba6a88a3355697735626 Mon Sep 17 00:00:00 2001
From: Retspen <anatoliy.guskov@gmail.com>
Date: Fri, 27 Feb 2015 11:28:22 +0200
Subject: [PATCH] build new tree

---
 computes/views.py                             |  18 +-
 instances/views.py                            |   4 +-
 interfaces/forms.py                           |  73 +++++++
 interfaces/views.py                           |  96 ++++++++-
 networks/forms.py                             |  43 ++++
 networks/views.py                             | 120 ++++++++++-
 secrets/forms.py                              |   8 +
 secrets/views.py                              |  58 +++++-
 {stotages => storages}/__init__.py            |   0
 {stotages => storages}/admin.py               |   0
 storages/forms.py                             |  87 ++++++++
 {stotages => storages}/migrations/__init__.py |   0
 {stotages => storages}/models.py              |   0
 {stotages => storages}/tests.py               |   0
 storages/views.py                             | 193 ++++++++++++++++++
 stotages/views.py                             |   3 -
 templates/compute.html                        |  44 +++-
 templates/computes.html                       |   5 +-
 templates/dashboard.html                      |  17 --
 templates/errors.html                         |   8 +
 templates/instances.html                      |   5 +-
 webvirtcloud/urls.py                          |  23 +--
 22 files changed, 745 insertions(+), 60 deletions(-)
 create mode 100644 interfaces/forms.py
 create mode 100644 networks/forms.py
 create mode 100644 secrets/forms.py
 rename {stotages => storages}/__init__.py (100%)
 rename {stotages => storages}/admin.py (100%)
 create mode 100644 storages/forms.py
 rename {stotages => storages}/migrations/__init__.py (100%)
 rename {stotages => storages}/models.py (100%)
 rename {stotages => storages}/tests.py (100%)
 create mode 100644 storages/views.py
 delete mode 100644 stotages/views.py
 delete mode 100644 templates/dashboard.html
 create mode 100644 templates/errors.html

diff --git a/computes/views.py b/computes/views.py
index 5152c91..c95bf25 100644
--- a/computes/views.py
+++ b/computes/views.py
@@ -14,7 +14,7 @@ def computes(request):
     """
 
     if not request.user.is_authenticated():
-        return HttpResponseRedirect(reverse('login'))
+        return HttpResponseRedirect(reverse('index'))
 
     def get_hosts_status(computes):
         """
@@ -23,13 +23,13 @@ def computes(request):
         compute_data = []
         for compute in computes:
             compute_data.append({'id': compute.id,
-                              'name': compute.name,
-                              'hostname': compute.hostname,
-                              'status': connection_manager.host_is_up(compute.type, compute.hostname),
-                              'type': compute.type,
-                              'login': compute.login,
-                              'password': compute.password
-                              })
+                                 'name': compute.name,
+                                 'hostname': compute.hostname,
+                                 'status': connection_manager.host_is_up(compute.type, compute.hostname),
+                                 'type': compute.type,
+                                 'login': compute.login,
+                                 'password': compute.password
+                                })
         return compute_data
 
     computes = Compute.objects.filter()
@@ -44,7 +44,7 @@ def compute(request, compute_id):
     """
 
     if not request.user.is_authenticated():
-        return HttpResponseRedirect(reverse('login'))
+        return HttpResponseRedirect(reverse('index'))
 
     errors = []
 
diff --git a/instances/views.py b/instances/views.py
index 037be61..00911e7 100644
--- a/instances/views.py
+++ b/instances/views.py
@@ -26,7 +26,7 @@ def instances(request):
     """
 
     if not request.user.is_authenticated():
-        return HttpResponseRedirect(reverse('login'))
+        return HttpResponseRedirect(reverse('index'))
 
     computes = Compute.objects.filter()
     all_host_vms = {}
@@ -50,6 +50,6 @@ def instance(request, comptes_id, vname):
     """
 
     if not request.user.is_authenticated():
-        return HttpResponseRedirect(reverse('login'))
+        return HttpResponseRedirect(reverse('index'))
 
     return render(request, 'instances.html', locals())
\ No newline at end of file
diff --git a/interfaces/forms.py b/interfaces/forms.py
new file mode 100644
index 0000000..cebd8a9
--- /dev/null
+++ b/interfaces/forms.py
@@ -0,0 +1,73 @@
+import re
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+
+class AddInterface(forms.Form):
+    name = forms.CharField(max_length=10, required=True)
+    itype = forms.ChoiceField(required=True, choices=(('bridge', 'bridge'), ('ethernet', 'ethernet')))
+    start_mode = forms.ChoiceField(required=True,
+                                   choices=(('none', 'none'), ('onboot', 'onboot'), ('hotplug', 'hotplug')))
+    netdev = forms.CharField(max_length=15, required=True)
+    ipv4_type = forms.ChoiceField(required=True, choices=(('dhcp', 'dhcp'), ('static', 'static'), ('none', 'none')))
+    ipv4_addr = forms.CharField(max_length=18, required=False)
+    ipv4_gw = forms.CharField(max_length=15, required=False)
+    ipv6_type = forms.ChoiceField(required=True, choices=(('dhcp', 'dhcp'), ('static', 'static'), ('none', 'none')))
+    ipv6_addr = forms.CharField(max_length=100, required=False)
+    ipv6_gw = forms.CharField(max_length=100, required=False)
+    stp = forms.ChoiceField(required=False, choices=(('on', 'on'), ('off', 'off')))
+    delay = forms.IntegerField(required=False)
+
+    def clean_ipv4_addr(self):
+        ipv4_addr = self.cleaned_data['ipv4_addr']
+        have_symbol = re.match('^[0-9./]+$', ipv4_addr)
+        if not have_symbol:
+            raise forms.ValidationError(_('The ipv4 must not contain any special characters'))
+        elif len(ipv4_addr) > 20:
+            raise forms.ValidationError(_('The ipv4 must not exceed 20 characters'))
+        return ipv4_addr
+
+    def clean_ipv4_gw(self):
+        ipv4_gw = self.cleaned_data['ipv4_gw']
+        have_symbol = re.match('^[0-9.]+$', ipv4_gw)
+        if not have_symbol:
+            raise forms.ValidationError(_('The ipv4 gateway must not contain any special characters'))
+        elif len(ipv4_gw) > 20:
+            raise forms.ValidationError(_('The ipv4 gateway must not exceed 20 characters'))
+        return ipv4_gw
+
+    def clean_ipv6_addr(self):
+        ipv6_addr = self.cleaned_data['ipv6_addr']
+        have_symbol = re.match('^[0-9a-f./:]+$', ipv6_addr)
+        if not have_symbol:
+            raise forms.ValidationError(_('The ipv6 must not contain any special characters'))
+        elif len(ipv6_addr) > 100:
+            raise forms.ValidationError(_('The ipv6 must not exceed 100 characters'))
+        return ipv6_addr
+
+    def clean_ipv6_gw(self):
+        ipv6_gw = self.cleaned_data['ipv6_gw']
+        have_symbol = re.match('^[0-9.]+$', ipv6_gw)
+        if not have_symbol:
+            raise forms.ValidationError(_('The ipv6 gateway must not contain any special characters'))
+        elif len(ipv6_gw) > 100:
+            raise forms.ValidationError(_('The ipv6 gateway must not exceed 100 characters'))
+        return ipv6_gw
+
+    def clean_name(self):
+        name = self.cleaned_data['name']
+        have_symbol = re.match('^[a-z0-9.]+$', name)
+        if not have_symbol:
+            raise forms.ValidationError(_('The interface must not contain any special characters'))
+        elif len(name) > 10:
+            raise forms.ValidationError(_('The interface must not exceed 10 characters'))
+        return name
+
+    def clean_netdev(self):
+        netdev = self.cleaned_data['netdev']
+        have_symbol = re.match('^[a-z0-9.]+$', netdev)
+        if not have_symbol:
+            raise forms.ValidationError(_('The interface must not contain any special characters'))
+        elif len(netdev) > 10:
+            raise forms.ValidationError(_('The interface must not exceed 10 characters'))
+        return netdev
diff --git a/interfaces/views.py b/interfaces/views.py
index 91ea44a..6b06be4 100644
--- a/interfaces/views.py
+++ b/interfaces/views.py
@@ -1,3 +1,97 @@
 from django.shortcuts import render
+from django.http import HttpResponseRedirect
+from django.core.urlresolvers import reverse
+from computes.models import Compute
+from interfaces.forms import AddInterface
+from vrtManager.interface import wvmInterface, wvmInterfaces
+from libvirt import libvirtError
 
-# Create your views here.
+
+def interfaces(request, compute_id):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    errors = []
+    ifaces_all = []
+    compute = Compute.objects.get(id=compute_id)
+
+    try:
+        conn = wvmInterfaces(compute.hostname,
+                             compute.login,
+                             compute.password,
+                             compute.type)
+        ifaces = conn.get_ifaces()
+        try:
+            netdevs = conn.get_net_device()
+        except:
+            netdevs = ['eth0', 'eth1']
+
+        for iface in ifaces:
+            ifaces_all.append(conn.get_iface_info(iface))
+
+        if request.method == 'POST':
+            if 'create' in request.POST:
+                form = AddInterface(request.POST)
+                if form.is_valid():
+                    data = form.cleaned_data
+                    conn.create_iface(data['name'], data['itype'], data['start_mode'], data['netdev'],
+                                      data['ipv4_type'], data['ipv4_addr'], data['ipv4_gw'],
+                                      data['ipv6_type'], data['ipv6_addr'], data['ipv6_gw'],
+                                      data['stp'], data['delay'])
+                    return HttpResponseRedirect(request.get_full_path())
+        conn.close()
+    except libvirtError as err:
+        errors.append(err)
+
+    return render(request, 'interfaces.html', locals())
+
+
+def interface(request, compute_id, iface):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    errors = []
+    ifaces_all = []
+    compute = Compute.objects.get(id=compute_id)
+
+    try:
+        conn = wvmInterface(compute.hostname,
+                            compute.login,
+                            compute.password,
+                            compute.type,
+                            iface)
+        start_mode = conn.get_start_mode()
+        state = conn.is_active()
+        mac = conn.get_mac()
+        itype = conn.get_type()
+        ipv4 = conn.get_ipv4()
+        ipv4_type = conn.get_ipv4_type()
+        ipv6 = conn.get_ipv6()
+        ipv6_type = conn.get_ipv6_type()
+        bridge = conn.get_bridge()
+
+        if request.method == 'POST':
+            if 'stop' in request.POST:
+                conn.stop_iface()
+                return HttpResponseRedirect(request.get_full_path())
+            if 'start' in request.POST:
+                conn.start_iface()
+                return HttpResponseRedirect(request.get_full_path())
+            if 'delete' in request.POST:
+                conn.delete_iface()
+                return HttpResponseRedirect(reverse('interfaces', args=[host_id]))
+        conn.close()
+    except libvirtError as err:
+        errors.append(err)
+
+    return render(request, 'interface.html', locals())
diff --git a/networks/forms.py b/networks/forms.py
new file mode 100644
index 0000000..3d44433
--- /dev/null
+++ b/networks/forms.py
@@ -0,0 +1,43 @@
+import re
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+
+class AddNetPool(forms.Form):
+    name = forms.CharField(error_messages={'required': _('No pool name has been entered')},
+                           max_length=20)
+    subnet = forms.CharField(error_messages={'required': _('No subnet has been entered')},
+                             max_length=20)
+    forward = forms.CharField(max_length=100)
+    dhcp = forms.BooleanField(required=False)
+    fixed = forms.BooleanField(required=False)
+    bridge_name = forms.CharField(max_length=20, required=False)
+    openvswitch = forms.BooleanField(required=False)
+
+    def clean_name(self):
+        name = self.cleaned_data['name']
+        have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+        if not have_symbol:
+            raise forms.ValidationError(_('The pool name must not contain any special characters'))
+        elif len(name) > 20:
+            raise forms.ValidationError(_('The pool name must not exceed 20 characters'))
+        return name
+
+    def clean_subnet(self):
+        subnet = self.cleaned_data['subnet']
+        have_symbol = re.match('^[0-9./]+$', subnet)
+        if not have_symbol:
+            raise forms.ValidationError(_('The pool subnet must not contain any special characters'))
+        elif len(subnet) > 20:
+            raise forms.ValidationError(_('The pool subnet must not exceed 20 characters'))
+        return subnet
+
+    def clean_bridge_name(self):
+        bridge_name = self.cleaned_data['bridge_name']
+        if self.cleaned_data['forward'] == 'bridge':
+            have_symbol = re.match('^[a-zA-Z0-9._-]+$', bridge_name)
+            if not have_symbol:
+                raise forms.ValidationError(_('The pool bridge name must not contain any special characters'))
+            elif len(bridge_name) > 20:
+                raise forms.ValidationError(_('The pool bridge name must not exceed 20 characters'))
+            return bridge_name
diff --git a/networks/views.py b/networks/views.py
index 91ea44a..ae59255 100644
--- a/networks/views.py
+++ b/networks/views.py
@@ -1,3 +1,121 @@
 from django.shortcuts import render
+from django.http import HttpResponseRedirect
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse
+from computes.models import Compute
+from networks.forms import AddNetPool
+from vrtManager.network import wvmNetwork, wvmNetworks
+from vrtManager.network import network_size
+from libvirt import libvirtError
 
-# Create your views here.
+
+def networks(request, compute_id):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    errors = []
+    compute = Compute.objects.get(id=compute_id)
+
+    try:
+        conn = wvmNetworks(compute.hostname,
+                           compute.login,
+                           compute.password,
+                           compute.type)
+        networks = conn.get_networks_info()
+
+        if request.method == 'POST':
+            if 'create' in request.POST:
+                form = AddNetPool(request.POST)
+                if form.is_valid():
+                    data = form.cleaned_data
+                    if data['name'] in networks:
+                        msg = _("Pool name already in use")
+                        errors.append(msg)
+                    if data['forward'] == 'bridge' and data['bridge_name'] == '':
+                        errors.append('Please enter bridge name')
+                    try:
+                        gateway, netmask, dhcp = network_size(data['subnet'], data['dhcp'])
+                    except:
+                        msg = _("Input subnet pool error")
+                        errors.append(msg)
+                    if not errors:
+                        conn.create_network(data['name'], data['forward'], gateway, netmask,
+                                            dhcp, data['bridge_name'], data['openvswitch'], data['fixed'])
+                        return HttpResponseRedirect(reverse('network', args=[host_id, data['name']]))
+        conn.close()
+    except libvirtError as err:
+        errors.append(err)
+
+    return render(request, 'network.html', locals())
+
+
+def network(request, compute_id, pool):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    errors = []
+    compute = Compute.objects.get(id=compute_id)
+
+    try:
+        conn = wvmNetwork(compute.hostname,
+                          compute.login,
+                          compute.password,
+                          compute.type,
+                          pool)
+        networks = conn.get_networks()
+        state = conn.is_active()
+        device = conn.get_bridge_device()
+        autostart = conn.get_autostart()
+        ipv4_forward = conn.get_ipv4_forward()
+        ipv4_dhcp_range_start = conn.get_ipv4_dhcp_range_start()
+        ipv4_dhcp_range_end = conn.get_ipv4_dhcp_range_end()
+        ipv4_network = conn.get_ipv4_network()
+        fixed_address = conn.get_mac_ipaddr()
+    except libvirtError as err:
+        errors.append(err)
+
+    if request.method == 'POST':
+        if 'start' in request.POST:
+            try:
+                conn.start()
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'stop' in request.POST:
+            try:
+                conn.stop()
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'delete' in request.POST:
+            try:
+                conn.delete()
+                return HttpResponseRedirect(reverse('networks', args=[host_id]))
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'set_autostart' in request.POST:
+            try:
+                conn.set_autostart(1)
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'unset_autostart' in request.POST:
+            try:
+                conn.set_autostart(0)
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+
+    conn.close()
+
+    return render(request, 'network.html', locals())
diff --git a/secrets/forms.py b/secrets/forms.py
new file mode 100644
index 0000000..7ae478e
--- /dev/null
+++ b/secrets/forms.py
@@ -0,0 +1,8 @@
+from django import forms
+
+
+class AddSecret(forms.Form):
+    ephemeral = forms.ChoiceField(required=True, choices=(('no', 'no'), ('yes', 'yes')))
+    private = forms.ChoiceField(required=True, choices=(('no', 'no'), ('yes', 'yes')))
+    usage_type = forms.ChoiceField(required=True, choices=(('ceph', 'ceph'), ('volume', 'volume'), ('iscsi', 'iscsi')))
+    data = forms.CharField(max_length=100, required=True)
diff --git a/secrets/views.py b/secrets/views.py
index 91ea44a..af03f93 100644
--- a/secrets/views.py
+++ b/secrets/views.py
@@ -1,3 +1,59 @@
 from django.shortcuts import render
+from django.http import HttpResponseRedirect
+from django.core.urlresolvers import reverse
+from computes.models import Compute
+from secrets.forms import AddSecret
+from vrtManager.secrets import wvmSecrets
+from libvirt import libvirtError
 
-# Create your views here.
+
+def secrets(request, compute_id):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    errors = []
+    secrets_all = []
+    compute = Compute.objects.get(id=compute_id)
+
+    try:
+        conn = wvmSecrets(compute.hostname,
+                          compute.login,
+                          compute.password,
+                          compute.type)
+        secrets = conn.get_secrets()
+        for uuid in secrets:
+            secrt = conn.get_secret(uuid)
+            try:
+                secret_value = conn.get_secret_value(uuid)
+            except:
+                secret_value = ''
+            secrets_all.append({'usage': secrt.usageID(),
+                                'uuid': secrt.UUIDString(),
+                                'usageType': secrt.usageType(),
+                                'value': secret_value
+                                })
+        if request.method == 'POST':
+            if 'create' in request.POST:
+                form = AddSecret(request.POST)
+                if form.is_valid():
+                    data = form.cleaned_data
+                    conn.create_secret(data['ephemeral'], data['private'], data['usage_type'], data['data'])
+                    return HttpResponseRedirect(request.get_full_path())
+            if 'delete' in request.POST:
+                uuid = request.POST.get('uuid', '')
+                conn.delete_secret(uuid)
+                return HttpResponseRedirect(request.get_full_path())
+            if 'set_value' in request.POST:
+                uuid = request.POST.get('uuid', '')
+                value = request.POST.get('value', '')
+                conn.set_secret_value(uuid, value)
+                return HttpResponseRedirect(request.get_full_path())
+    except libvirtError as err:
+        errors.append(err)
+
+    return render(request, 'secrets.html', locals())
diff --git a/stotages/__init__.py b/storages/__init__.py
similarity index 100%
rename from stotages/__init__.py
rename to storages/__init__.py
diff --git a/stotages/admin.py b/storages/admin.py
similarity index 100%
rename from stotages/admin.py
rename to storages/admin.py
diff --git a/storages/forms.py b/storages/forms.py
new file mode 100644
index 0000000..e2114ee
--- /dev/null
+++ b/storages/forms.py
@@ -0,0 +1,87 @@
+import re
+from django import forms
+from django.utils.translation import ugettext_lazy as _
+
+
+class AddStgPool(forms.Form):
+    name = forms.CharField(error_messages={'required': _('No pool name has been entered')},
+                           max_length=20)
+    stg_type = forms.CharField(max_length=10)
+    target = forms.CharField(error_messages={'required': _('No path has been entered')},
+                             max_length=100,
+                             required=False)
+    source = forms.CharField(max_length=100, required=False)
+    ceph_user = forms.CharField(required=False)
+    ceph_host = forms.CharField(required=False)
+    ceph_pool = forms.CharField(required=False)
+    secret = forms.CharField(required=False)
+    netfs_host = forms.CharField(required=False)
+    source_format = forms.CharField(required=False)
+
+    def clean_name(self):
+        name = self.cleaned_data['name']
+        have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+        if not have_symbol:
+            raise forms.ValidationError(_('The pool name must not contain any special characters'))
+        elif len(name) > 20:
+            raise forms.ValidationError(_('The pool name must not exceed 20 characters'))
+        return name
+
+    def clean_target(self):
+        storage_type = self.cleaned_data['stg_type']
+        target = self.cleaned_data['target']
+        have_symbol = re.match('^[a-zA-Z0-9/]+$', target)
+        if not have_symbol:
+            raise forms.ValidationError(_('The target must not contain any special characters'))
+        if storage_type == 'dir':
+            if not target:
+                raise forms.ValidationError(_('No path has been entered'))
+        return target
+
+    def clean_source(self):
+        storage_type = self.cleaned_data['stg_type']
+        source = self.cleaned_data['source']
+        have_symbol = re.match('^[a-zA-Z0-9\/]+$', source)
+        if storage_type == 'logical' or storage_type == 'netfs':
+            if not source:
+                raise forms.ValidationError(_('No device has been entered'))
+            if not have_symbol:
+                raise forms.ValidationError(_('The source must not contain any special characters'))
+        return source
+
+
+class AddImage(forms.Form):
+    name = forms.CharField(max_length=20)
+    format = forms.ChoiceField(required=True, choices=(('qcow2', 'qcow2 (recommended)'),
+                                                       ('qcow', 'qcow'),
+                                                       ('raw', 'raw')))
+    size = forms.IntegerField()
+    meta_prealloc = forms.BooleanField(required=False)
+
+    def clean_name(self):
+        name = self.cleaned_data['name']
+        have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+        if not have_symbol:
+            raise forms.ValidationError(_('The image name must not contain any special characters'))
+        elif len(name) > 20:
+            raise forms.ValidationError(_('The image name must not exceed 20 characters'))
+        return name
+
+
+class CloneImage(forms.Form):
+    name = forms.CharField(max_length=20)
+    image = forms.CharField(max_length=20)
+    convert = forms.BooleanField(required=False)
+    format = forms.ChoiceField(required=False, choices=(('qcow2', 'qcow2 (recommended)'),
+                                                        ('qcow', 'qcow'),
+                                                        ('raw', 'raw')))
+    meta_prealloc = forms.BooleanField(required=False)
+
+    def clean_name(self):
+        name = self.cleaned_data['name']
+        have_symbol = re.match('^[a-zA-Z0-9._-]+$', name)
+        if not have_symbol:
+            raise forms.ValidationError(_('The image name must not contain any special characters'))
+        elif len(name) > 20:
+            raise forms.ValidationError(_('The image name must not exceed 20 characters'))
+        return name
diff --git a/stotages/migrations/__init__.py b/storages/migrations/__init__.py
similarity index 100%
rename from stotages/migrations/__init__.py
rename to storages/migrations/__init__.py
diff --git a/stotages/models.py b/storages/models.py
similarity index 100%
rename from stotages/models.py
rename to storages/models.py
diff --git a/stotages/tests.py b/storages/tests.py
similarity index 100%
rename from stotages/tests.py
rename to storages/tests.py
diff --git a/storages/views.py b/storages/views.py
new file mode 100644
index 0000000..0b5351b
--- /dev/null
+++ b/storages/views.py
@@ -0,0 +1,193 @@
+from django.shortcuts import render
+from django.http import HttpResponseRedirect
+from django.utils.translation import ugettext_lazy as _
+from django.core.urlresolvers import reverse
+from computes.models import Compute
+from storages.forms import AddStgPool, AddImage, CloneImage
+from vrtManager.storage import wvmStorage, wvmStorages
+from libvirt import libvirtError
+
+
+def storages(request, compute_id):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    errors = []
+    compute = Compute.objects.get(id=compute_id)
+
+    try:
+        conn = wvmStorages(compute.hostname,
+                           compute.login,
+                           compute.password,
+                           compute.type)
+        storages = conn.get_storages_info()
+        secrets = conn.get_secrets()
+
+        if request.method == 'POST':
+            if 'create' in request.POST:
+                form = AddStgPool(request.POST)
+                if form.is_valid():
+                    data = form.cleaned_data
+                    if data['name'] in storages:
+                        msg = _("Pool name already use")
+                        errors.append(msg)
+                    if data['stg_type'] == 'rbd':
+                        if not data['secret']:
+                            msg = _("You need create secret for pool")
+                            errors.append(msg)
+                        if not data['ceph_pool'] and not data['ceph_host'] and not data['ceph_user']:
+                            msg = _("You need input all fields for creating ceph pool")
+                            errors.append(msg)
+                    if not errors:
+                        if data['stg_type'] == 'rbd':
+                            conn.create_storage_ceph(data['stg_type'], data['name'],
+                                                     data['ceph_pool'], data['ceph_host'],
+                                                     data['ceph_user'], data['secret'])
+                        elif data['stg_type'] == 'netfs':
+                            conn.create_storage_netfs(data['stg_type'], data['name'],
+                                                      data['netfs_host'], data['source'],
+                                                      data['source_format'], data['target'])
+                        else:
+                            conn.create_storage(data['stg_type'], data['name'], data['source'], data['target'])
+                        return HttpResponseRedirect(reverse('storage', args=[host_id, data['name']]))
+        conn.close()
+    except libvirtError as err:
+        errors.append(err)
+
+    return render(request, 'storages.html', locals())
+
+
+def storage(request, compute_id, pool):
+    """
+    :param request:
+    :return:
+    """
+
+    if not request.user.is_authenticated():
+        return HttpResponseRedirect(reverse('index'))
+
+    def handle_uploaded_file(path, f_name):
+        target = path + '/' + str(f_name)
+        destination = open(target, 'wb+')
+        for chunk in f_name.chunks():
+            destination.write(chunk)
+        destination.close()
+
+    errors = []
+    compute = Compute.objects.get(id=compute_id)
+    meta_prealloc = False
+
+    try:
+        conn = wvmStorage(compute.hostname,
+                          compute.login,
+                          compute.password,
+                          compute.type,
+                          pool)
+
+        storages = conn.get_storages()
+        state = conn.is_active()
+        size, free = conn.get_size()
+        used = (size - free)
+        if state:
+            percent = (used * 100) / size
+        else:
+            percent = 0
+        status = conn.get_status()
+        path = conn.get_target_path()
+        type = conn.get_type()
+        autostart = conn.get_autostart()
+
+        if state:
+            conn.refresh()
+            volumes = conn.update_volumes()
+        else:
+            volumes = None
+    except libvirtError as err:
+        errors.append(err)
+
+    if request.method == 'POST':
+        if 'start' in request.POST:
+            try:
+                conn.start()
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'stop' in request.POST:
+            try:
+                conn.stop()
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'delete' in request.POST:
+            try:
+                conn.delete()
+                return HttpResponseRedirect(reverse('storages', args=[host_id]))
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'set_autostart' in request.POST:
+            try:
+                conn.set_autostart(1)
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'unset_autostart' in request.POST:
+            try:
+                conn.set_autostart(0)
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'add_volume' in request.POST:
+            form = AddImage(request.POST)
+            if form.is_valid():
+                data = form.cleaned_data
+                if data['meta_prealloc'] and data['format'] == 'qcow2':
+                    meta_prealloc = True
+                try:
+                    conn.create_volume(data['name'], data['size'], data['format'], meta_prealloc)
+                    return HttpResponseRedirect(request.get_full_path())
+                except libvirtError as err:
+                    errors.append(err)
+        if 'del_volume' in request.POST:
+            volname = request.POST.get('volname', '')
+            try:
+                vol = conn.get_volume(volname)
+                vol.delete(0)
+                return HttpResponseRedirect(request.get_full_path())
+            except libvirtError as error_msg:
+                errors.append(error_msg.message)
+        if 'iso_upload' in request.POST:
+            if str(request.FILES['file']) in conn.update_volumes():
+                msg = _("ISO image already exist")
+                errors.append(msg)
+            else:
+                handle_uploaded_file(path, request.FILES['file'])
+                return HttpResponseRedirect(request.get_full_path())
+        if 'cln_volume' in request.POST:
+            form = CloneImage(request.POST)
+            if form.is_valid():
+                data = form.cleaned_data
+                img_name = data['name'] + '.img'
+                meta_prealloc = 0
+                if img_name in conn.update_volumes():
+                    msg = _("Name of volume name already use")
+                    errors.append(msg)
+                if not errors:
+                    if data['convert']:
+                        format = data['format']
+                        if data['meta_prealloc'] and data['format'] == 'qcow2':
+                            meta_prealloc = True
+                    else:
+                        format = None
+                    try:
+                        conn.clone_volume(data['image'], data['name'], format, meta_prealloc)
+                        return HttpResponseRedirect(request.get_full_path())
+                    except libvirtError as err:
+                        errors.append(err)
+    conn.close()
+
+    return render(request, 'storage.html', locals())
diff --git a/stotages/views.py b/stotages/views.py
deleted file mode 100644
index 91ea44a..0000000
--- a/stotages/views.py
+++ /dev/null
@@ -1,3 +0,0 @@
-from django.shortcuts import render
-
-# Create your views here.
diff --git a/templates/compute.html b/templates/compute.html
index 92f11b1..068a0f9 100644
--- a/templates/compute.html
+++ b/templates/compute.html
@@ -9,15 +9,47 @@
 
         <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
             <button type="button" class="btn btn-success pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button>
-            <h1 class="page-header">Computes</h1>
+            <h1 class="page-header">{{ compute.name }}</h1>
 
-            <div class="alert alert-danger alert-dismissible" role="danger">
-              <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-              <strong>Error:</strong> Better check yourself, you're not looking too good.
+            {% include 'errors.html' %}
+
+            <h4>{% trans "Basic details" %}</h4>
+
+            <div class="table-responsive">
+                <table class="table">
+                    <tbody>
+                        <tr>
+                            <td>{% trans "Connection" %}</td>
+                            <td>{{ uri_conn }}</td>
+                        </tr>
+                        <tr>
+                            <td>{% trans "Hostname" %}</td>
+                            <td>{{ hostname }}</td>
+                        </tr>
+                        <tr>
+                            <td>{% trans "Hypervisor" %}</td>
+                            <td>{{ hypervisor }}</td>
+                        </tr>
+                        <tr>
+                            <td>{% trans "Memory" %}</td>
+                            <td>{{ host_memory|filesizeformat }}</td>
+                        </tr>
+                        <tr>
+                            <td>{% trans "Logical CPUs" %}</td>
+                            <td>{{ logical_cpu }}</td>
+                        </tr>
+                        <tr>
+                            <td>{% trans "Processor" %}</td>
+                            <td>{{ model_cpu }}</td>
+                        </tr>
+                        <tr>
+                            <td>{% trans "Architecture" %}</td>
+                            <td>{{ host_arch }}</td>
+                        </tr>
+                    </tbody>
+                </table>
             </div>
 
-
-
         </div>
     </div>
 </div>
diff --git a/templates/computes.html b/templates/computes.html
index 18ff94b..03eb4cf 100644
--- a/templates/computes.html
+++ b/templates/computes.html
@@ -11,10 +11,7 @@
             <button type="button" class="btn btn-success pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button>
             <h1 class="page-header">Computes</h1>
 
-            <div class="alert alert-danger alert-dismissible" role="danger">
-              <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-              <strong>Error:</strong> Better check yourself, you're not looking too good.
-            </div>
+            {% include 'errors.html' %}
 
             <div class="row">
                 {% if computes_info %}
diff --git a/templates/dashboard.html b/templates/dashboard.html
deleted file mode 100644
index c8f7ef6..0000000
--- a/templates/dashboard.html
+++ /dev/null
@@ -1,17 +0,0 @@
-{% load static %}
-{% include 'header.html' %}
-<body>
-<div class="container-fluid">
-    <div class="row">
-
-        {% include 'sidebar.html' %}
-
-        <div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main">
-            <h1 class="page-header">Dashboard</h1>
-
-
-        </div>
-    </div>
-</div>
-
-{% include 'footer.html' %}
diff --git a/templates/errors.html b/templates/errors.html
new file mode 100644
index 0000000..0399b80
--- /dev/null
+++ b/templates/errors.html
@@ -0,0 +1,8 @@
+            {% if errors %}
+                {% for error in errors %}
+                    <div class="alert alert-danger alert-dismissible" role="danger">
+                      <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
+                      <strong>Error:</strong> Better check yourself, you're not looking too good.
+                    </div>
+                {% endfor %}
+            {% endif %}
\ No newline at end of file
diff --git a/templates/instances.html b/templates/instances.html
index 12bef53..cb005a4 100644
--- a/templates/instances.html
+++ b/templates/instances.html
@@ -11,10 +11,7 @@
             <button type="button" class="btn btn-success pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button>
             <h1 class="page-header">Instances</h1>
 
-            <div class="alert alert-danger alert-dismissible" role="danger">
-              <button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button>
-              <strong>Error:</strong> Better check yourself, you're not looking too good.
-            </div>
+            {% include 'errors.html' %}
 
             <div class="table-responsive">
                 <table class="table">
diff --git a/webvirtcloud/urls.py b/webvirtcloud/urls.py
index aa5de51..060d115 100644
--- a/webvirtcloud/urls.py
+++ b/webvirtcloud/urls.py
@@ -15,18 +15,17 @@ urlpatterns = patterns('',
     url(r'^computes/$', 'computes.views.computes', name='computes'),
     url(r'^compute/(\d+)/$', 'computes.views.compute', name='compute'),
 
-    # url(r'^storages/$', 'storages.views.storages', name='storages'),
-    # url(r'^storage/(\d+)/([\w\-\.]+)/$', 'storages.views.storage', name='storage'),
-    #
-    # url(r'^networks/$', 'networks.views.networks', name='networks'),
-    # url(r'^network/(\d+)/([\w\-\.]+)/$', 'networks.views.network', name='network'),
-    #
-    # url(r'^interfaces/$', 'interfaces.views.interfaces', name='interfaces'),
-    # url(r'^interface/(\d+)/([\w\.]+)$', 'interfaces.views.interface', name='interface'),
-    #
-    # url(r'^secrets/$', 'secrets.views.secrets', name='secrets'),
-    # url(r'^secret/(\d+)/([\w\.]+)$', 'secrets.views.secret', name='secret'),
-    #
+    url(r'^storages/(\d+)/$', 'storages.views.storages', name='storages'),
+    url(r'^storage/(\d+)/([\w\-\.]+)/$', 'storages.views.storage', name='storage'),
+
+    url(r'^networks/(\d+)/$', 'networks.views.networks', name='networks'),
+    url(r'^network/(\d+)/([\w\-\.]+)/$', 'networks.views.network', name='network'),
+
+    url(r'^interfaces/(\d+)/$', 'interfaces.views.interfaces', name='interfaces'),
+    url(r'^interface/(\d+)/([\w\.]+)$', 'interfaces.views.interface', name='interface'),
+
+    url(r'^secret/(\d+)/$', 'secrets.views.secrets', name='secrets'),
+
     # url(r'^accounts/$', 'accounts.views.accounts', name='accounts'),
     # url(r'^account/(\d+)/$', 'accounts.views.account', name='account'),
     #