mirror of
https://github.com/retspen/webvirtcloud
synced 2025-07-31 12:41:08 +00:00
build new tree
This commit is contained in:
parent
4d48e79341
commit
dd5f98cbe8
22 changed files with 745 additions and 60 deletions
0
storages/__init__.py
Normal file
0
storages/__init__.py
Normal file
3
storages/admin.py
Normal file
3
storages/admin.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
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
|
||||
0
storages/migrations/__init__.py
Normal file
0
storages/migrations/__init__.py
Normal file
3
storages/models.py
Normal file
3
storages/models.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
3
storages/tests.py
Normal file
3
storages/tests.py
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
||||
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())
|
||||
Loading…
Add table
Add a link
Reference in a new issue