mirror of
https://github.com/retspen/webvirtcloud
synced 2024-12-24 23:25:24 +00:00
build new tree
This commit is contained in:
parent
4d48e79341
commit
dd5f98cbe8
22 changed files with 745 additions and 60 deletions
|
@ -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):
|
||||
"""
|
||||
|
@ -44,7 +44,7 @@ def compute(request, compute_id):
|
|||
"""
|
||||
|
||||
if not request.user.is_authenticated():
|
||||
return HttpResponseRedirect(reverse('login'))
|
||||
return HttpResponseRedirect(reverse('index'))
|
||||
|
||||
errors = []
|
||||
|
||||
|
|
|
@ -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
73
interfaces/forms.py
Normal 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
|
|
@ -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
43
networks/forms.py
Normal 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
|
|
@ -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
8
secrets/forms.py
Normal 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)
|
|
@ -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
87
storages/forms.py
Normal 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
193
storages/views.py
Normal 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())
|
|
@ -1,3 +0,0 @@
|
|||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
|
@ -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">×</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>
|
||||
|
|
|
@ -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">×</span></button>
|
||||
<strong>Error:</strong> Better check yourself, you're not looking too good.
|
||||
</div>
|
||||
{% include 'errors.html' %}
|
||||
|
||||
<div class="row">
|
||||
{% if computes_info %}
|
||||
|
|
|
@ -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
8
templates/errors.html
Normal 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">×</span></button>
|
||||
<strong>Error:</strong> Better check yourself, you're not looking too good.
|
||||
</div>
|
||||
{% endfor %}
|
||||
{% endif %}
|
|
@ -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">×</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">
|
||||
|
|
|
@ -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'),
|
||||
#
|
||||
|
|
Loading…
Reference in a new issue