1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2025-01-12 08:25:18 +00:00

build new tree

This commit is contained in:
Retspen 2015-02-27 11:28:22 +02:00
parent 4d48e79341
commit dd5f98cbe8
22 changed files with 745 additions and 60 deletions

View file

@ -14,7 +14,7 @@ def computes(request):
""" """
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login')) return HttpResponseRedirect(reverse('index'))
def get_hosts_status(computes): def get_hosts_status(computes):
""" """
@ -23,13 +23,13 @@ def computes(request):
compute_data = [] compute_data = []
for compute in computes: for compute in computes:
compute_data.append({'id': compute.id, compute_data.append({'id': compute.id,
'name': compute.name, 'name': compute.name,
'hostname': compute.hostname, 'hostname': compute.hostname,
'status': connection_manager.host_is_up(compute.type, compute.hostname), 'status': connection_manager.host_is_up(compute.type, compute.hostname),
'type': compute.type, 'type': compute.type,
'login': compute.login, 'login': compute.login,
'password': compute.password 'password': compute.password
}) })
return compute_data return compute_data
computes = Compute.objects.filter() computes = Compute.objects.filter()
@ -44,7 +44,7 @@ def compute(request, compute_id):
""" """
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login')) return HttpResponseRedirect(reverse('index'))
errors = [] errors = []

View file

@ -26,7 +26,7 @@ def instances(request):
""" """
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login')) return HttpResponseRedirect(reverse('index'))
computes = Compute.objects.filter() computes = Compute.objects.filter()
all_host_vms = {} all_host_vms = {}
@ -50,6 +50,6 @@ def instance(request, comptes_id, vname):
""" """
if not request.user.is_authenticated(): if not request.user.is_authenticated():
return HttpResponseRedirect(reverse('login')) return HttpResponseRedirect(reverse('index'))
return render(request, 'instances.html', locals()) return render(request, 'instances.html', locals())

73
interfaces/forms.py Normal file
View file

@ -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

View file

@ -1,3 +1,97 @@
from django.shortcuts import render 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())

43
networks/forms.py Normal file
View file

@ -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

View file

@ -1,3 +1,121 @@
from django.shortcuts import render 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())

8
secrets/forms.py Normal file
View file

@ -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)

View file

@ -1,3 +1,59 @@
from django.shortcuts import render 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())

87
storages/forms.py Normal file
View file

@ -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

193
storages/views.py Normal file
View file

@ -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())

View file

@ -1,3 +0,0 @@
from django.shortcuts import render
# Create your views here.

View file

@ -9,15 +9,47 @@
<div class="col-sm-9 col-sm-offset-3 col-md-10 col-md-offset-2 main"> <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> <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"> {% include 'errors.html' %}
<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. <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>
</div> </div>
</div> </div>

View file

@ -11,10 +11,7 @@
<button type="button" class="btn btn-success pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button> <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">Computes</h1>
<div class="alert alert-danger alert-dismissible" role="danger"> {% include 'errors.html' %}
<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>
<div class="row"> <div class="row">
{% if computes_info %} {% if computes_info %}

View file

@ -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' %}

8
templates/errors.html Normal file
View file

@ -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 %}

View file

@ -11,10 +11,7 @@
<button type="button" class="btn btn-success pull-right"><span class="glyphicon glyphicon-plus" aria-hidden="true"></span></button> <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> <h1 class="page-header">Instances</h1>
<div class="alert alert-danger alert-dismissible" role="danger"> {% include 'errors.html' %}
<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>
<div class="table-responsive"> <div class="table-responsive">
<table class="table"> <table class="table">

View file

@ -15,18 +15,17 @@ urlpatterns = patterns('',
url(r'^computes/$', 'computes.views.computes', name='computes'), url(r'^computes/$', 'computes.views.computes', name='computes'),
url(r'^compute/(\d+)/$', 'computes.views.compute', name='compute'), url(r'^compute/(\d+)/$', 'computes.views.compute', name='compute'),
# url(r'^storages/$', 'storages.views.storages', name='storages'), url(r'^storages/(\d+)/$', 'storages.views.storages', name='storages'),
# url(r'^storage/(\d+)/([\w\-\.]+)/$', 'storages.views.storage', name='storage'), url(r'^storage/(\d+)/([\w\-\.]+)/$', 'storages.views.storage', name='storage'),
#
# url(r'^networks/$', 'networks.views.networks', name='networks'), url(r'^networks/(\d+)/$', 'networks.views.networks', name='networks'),
# url(r'^network/(\d+)/([\w\-\.]+)/$', 'networks.views.network', name='network'), url(r'^network/(\d+)/([\w\-\.]+)/$', 'networks.views.network', name='network'),
#
# url(r'^interfaces/$', 'interfaces.views.interfaces', name='interfaces'), url(r'^interfaces/(\d+)/$', 'interfaces.views.interfaces', name='interfaces'),
# url(r'^interface/(\d+)/([\w\.]+)$', 'interfaces.views.interface', name='interface'), url(r'^interface/(\d+)/([\w\.]+)$', 'interfaces.views.interface', name='interface'),
#
# url(r'^secrets/$', 'secrets.views.secrets', name='secrets'), url(r'^secret/(\d+)/$', 'secrets.views.secrets', name='secrets'),
# url(r'^secret/(\d+)/([\w\.]+)$', 'secrets.views.secret', name='secret'),
#
# url(r'^accounts/$', 'accounts.views.accounts', name='accounts'), # url(r'^accounts/$', 'accounts.views.accounts', name='accounts'),
# url(r'^account/(\d+)/$', 'accounts.views.account', name='account'), # url(r'^account/(\d+)/$', 'accounts.views.account', name='account'),
# #