1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2024-12-24 15:15:22 +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():
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 = []

View file

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

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.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.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.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">
<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>

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

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

View file

@ -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'),
#