From f690d1fa60264b40519f94be5018fffd01bcb356 Mon Sep 17 00:00:00 2001 From: catborise Date: Mon, 6 Dec 2021 08:42:50 +0300 Subject: [PATCH 1/5] handle security concerns with file uploading --- storages/views.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/storages/views.py b/storages/views.py index 0c48ab6..18a3d02 100644 --- a/storages/views.py +++ b/storages/views.py @@ -1,4 +1,5 @@ import json +import os from django.contrib import messages from django.http import HttpResponse, HttpResponseRedirect @@ -90,7 +91,10 @@ def storage(request, compute_id, pool): """ def handle_uploaded_file(path, f_name): - target = path + "/" + str(f_name) + target = os.path.normpath(os.path.join(path, f_name)) + if not target.startswith(path): + raise Exception("Security Issues with file uploading") + destination = open(target, "wb+") for chunk in f_name.chunks(): destination.write(chunk) From 5c9a5daedc397601d79d35ec3af9879a7cf6199b Mon Sep 17 00:00:00 2001 From: catborise Date: Mon, 6 Dec 2021 09:22:02 +0300 Subject: [PATCH 2/5] remove eval for security concerns --- instances/templates/instances/settings_tab.html | 14 +++++++------- instances/views.py | 4 ++-- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/instances/templates/instances/settings_tab.html b/instances/templates/instances/settings_tab.html index 6426023..0728664 100644 --- a/instances/templates/instances/settings_tab.html +++ b/instances/templates/instances/settings_tab.html @@ -886,15 +886,15 @@
- - {% if instance.status == 5 %} + + {% if instance.status == 5 %} - {% else %} + {% else %} - {% endif %} + {% endif %}
diff --git a/instances/views.py b/instances/views.py index f8bcd2e..5cad4c6 100644 --- a/instances/views.py +++ b/instances/views.py @@ -793,9 +793,9 @@ def set_vcpu(request, pk): @superuser_only def set_vcpu_hotplug(request, pk): instance = get_instance(request.user, pk) - status = request.POST.get("vcpu_hotplug", "") + status = True if request.POST.get("vcpu_hotplug", "False") == 'True' else False msg = _("VCPU Hot-plug is enabled=%(status)s") % {"status": status} - instance.proxy.set_vcpu_hotplug(eval(status)) + instance.proxy.set_vcpu_hotplug(status) addlogmsg(request.user.username, instance.compute.name, instance.name, msg) return redirect(request.META.get("HTTP_REFERER") + "#resize") From 86723a82713229ecf3769086100cd827ef65ed60 Mon Sep 17 00:00:00 2001 From: catborise Date: Fri, 10 Dec 2021 14:39:56 +0300 Subject: [PATCH 3/5] add missing pipe mark after snapshot icon --- instances/templates/instance.html | 1 + 1 file changed, 1 insertion(+) diff --git a/instances/templates/instance.html b/instances/templates/instance.html index 03bad2f..a1b88b4 100644 --- a/instances/templates/instance.html +++ b/instances/templates/instance.html @@ -37,6 +37,7 @@ | {% if instance.snapshots %} + | {% endif %} {% if instance.cur_vcpu %} {{ instance.cur_vcpu }} {% trans "VCPU" %} From c77e049e82f8254eec466e54d7c85206de0c30e5 Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 16 Dec 2021 11:03:03 +0300 Subject: [PATCH 4/5] add rbd support for add new/existing vol. create from rbd based flavor --- instances/views.py | 39 ++++++++++++++++++++++++++++------- storages/views.py | 2 +- vrtManager/create.py | 46 +++++++++++++++++------------------------- vrtManager/instance.py | 34 ++++++++++++++++++++++++++----- vrtManager/storage.py | 41 ++++++++++++++++++++++++++++++++++--- 5 files changed, 119 insertions(+), 43 deletions(-) diff --git a/instances/views.py b/instances/views.py index 5cad4c6..e766bee 100644 --- a/instances/views.py +++ b/instances/views.py @@ -549,7 +549,24 @@ def add_new_vol(request, pk): int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_UID), int(app_settings.INSTANCE_VOLUME_DEFAULT_OWNER_GID), ) - instance.proxy.attach_disk(target_dev, source, target_bus=bus, driver_type=format, cache_mode=cache) + + conn_pool = wvmStorage( + instance.compute.hostname, + instance.compute.login, + instance.compute.password, + instance.compute.type, + storage, + ) + + pool_type = conn_pool.get_type() + disk_type = conn_pool.get_volume_type(os.path.basename(source)) + + if pool_type == 'rbd': + source_info = conn_pool.get_rbd_source() + else: # add more disk types to handle different pool and disk types + source_info = None + + instance.proxy.attach_disk(target_dev, source, source_info=source_info, pool_type=pool_type, disk_type=disk_type, target_bus=bus, format_type=format, cache_mode=cache) msg = _("Attach new disk: %(name)s (%(format)s)") % {"name": name, "format": format} addlogmsg(request.user.username, instance.compute.name, instance.name, msg) return redirect(request.META.get("HTTP_REFERER") + "#disks") @@ -575,12 +592,20 @@ def add_existing_vol(request, pk): storage, ) - driver_type = conn_create.get_volume_type(name) - path = conn_create.get_target_path() + format_type = conn_create.get_volume_format_type(name) + disk_type = conn_create.get_volume_type(name) + pool_type = conn_create.get_type() + if pool_type == 'rbd': + source_info = conn_create.get_rbd_source() + path = conn_create.get_source_name() + else: + source_info = None + path = conn_create.get_target_path() + target_dev = utils.get_new_disk_dev(media, disks, bus) source = f"{path}/{name}" - instance.proxy.attach_disk(target_dev, source, target_bus=bus, driver_type=driver_type, cache_mode=cache) + instance.proxy.attach_disk(target_dev, source, source_info=source_info, pool_type=pool_type, disk_type=disk_type, target_bus=bus, format_type=format_type, cache_mode=cache) msg = _("Attach Existing disk: %(target_dev)s") % {"target_dev": target_dev} addlogmsg(request.user.username, instance.compute.name, instance.name, msg) return redirect(request.META.get("HTTP_REFERER") + "#disks") @@ -1381,7 +1406,7 @@ def create_instance(request, compute_id, arch, machine): volume = dict() volume["device"] = "disk" volume["path"] = path - volume["type"] = conn.get_volume_type(path) + volume["type"] = conn.get_volume_format_type(path) volume["cache_mode"] = data["cache_mode"] volume["bus"] = default_bus if volume["bus"] == "scsi": @@ -1411,7 +1436,7 @@ def create_instance(request, compute_id, arch, machine): ) volume = dict() volume["path"] = clone_path - volume["type"] = conn.get_volume_type(clone_path) + volume["type"] = conn.get_volume_format_type(clone_path) volume["device"] = "disk" volume["cache_mode"] = data["cache_mode"] volume["bus"] = default_bus @@ -1431,7 +1456,7 @@ def create_instance(request, compute_id, arch, machine): path = conn.get_volume_path(vol) volume = dict() volume["path"] = path - volume["type"] = conn.get_volume_type(path) + volume["type"] = conn.get_volume_format_type(path) volume["device"] = request.POST.get("device" + str(idx), "") volume["bus"] = request.POST.get("bus" + str(idx), "") if volume["bus"] == "scsi": diff --git a/storages/views.py b/storages/views.py index 18a3d02..34681bd 100644 --- a/storages/views.py +++ b/storages/views.py @@ -145,7 +145,7 @@ def storage(request, compute_id, pool): volname = request.POST.get("volname", "") vol = conn.get_volume(volname) vol.delete(0) - messages.success(request, _("Volume: %(volume)s is deleted.") % {"vol": volname}) + messages.success(request, _("Volume: %(vol)s is deleted.") % {"vol": volname}) return redirect(reverse("storage", args=[compute.id, pool])) # return HttpResponseRedirect(request.get_full_path()) if "iso_upload" in request.POST: diff --git a/vrtManager/create.py b/vrtManager/create.py index fcae692..61d5040 100644 --- a/vrtManager/create.py +++ b/vrtManager/create.py @@ -11,9 +11,13 @@ def get_rbd_storage_data(stg): def get_ceph_hosts(doc): hosts = list() for host in doc.xpath("/pool/source/host"): - name = host.prop("name") + name = host.get('name') if name: - hosts.append({"name": name, "port": host.prop("port")}) + port = host.get('port') + if port: + hosts.append({"name": name, "port": port}) + else: + hosts.append({"name": name}) return hosts ceph_hosts = util.get_xml_path(xml, func=get_ceph_hosts) @@ -60,6 +64,7 @@ class wvmCreate(wvmConnect): name += ".img" alloc = 0 else: + image_format = 'raw' alloc = size metadata = False xml = f""" @@ -89,7 +94,7 @@ class wvmCreate(wvmConnect): vol = stg.storageVolLookupByName(name) return vol.path() - def get_volume_type(self, path): + def get_volume_format_type(self, path): vol = self.get_volume_by_path(path) vol_type = util.get_xml_path(vol.XMLDesc(0), "/volume/target/format/@type") if vol_type == "unknown" or vol_type == "iso": @@ -276,37 +281,24 @@ class wvmCreate(wvmConnect): if stg_type == "rbd": ceph_user, secret_uuid, ceph_hosts = get_rbd_storage_data(stg) - xml += """ - """ % ( - volume["type"], - disk_opts, - ) - xml += """ - + xml += f""" + """ + xml += f""" + - """ % ( - ceph_user, - secret_uuid, - volume["path"], - ) + """ if isinstance(ceph_hosts, list): for host in ceph_hosts: if host.get("port"): - xml += """ - """ % ( - host.get("name"), - host.get("port"), - ) + xml += f""" + """ else: - xml += """ - """ % host.get( - "name" - ) + xml += f"""""" xml += """""" else: - xml += """""" % volume["device"] - xml += """ """ % (volume["type"], disk_opts) - xml += """ """ % volume["path"] + xml += f"""""" + xml += f""" """ + xml += f""" """ if volume.get("bus") == "virtio": xml += """""" % (vd_disk_letters.pop(0), volume.get("bus")) diff --git a/vrtManager/instance.py b/vrtManager/instance.py index a59ec62..63fd835 100644 --- a/vrtManager/instance.py +++ b/vrtManager/instance.py @@ -713,11 +713,13 @@ class wvmInstance(wvmConnect): self, target_dev, source, + source_info = None, + pool_type="dir", target_bus="ide", disk_type="file", disk_device="disk", driver_name="qemu", - driver_type="raw", + format_type="raw", readonly=False, shareable=False, serial=None, @@ -739,11 +741,33 @@ class wvmInstance(wvmConnect): xml_disk = f"" if disk_device == "cdrom": - xml_disk += f"" + xml_disk += f"" elif disk_device == "disk": - xml_disk += f"" - xml_disk += f""" - """ + xml_disk += f"" + + if disk_type == 'file': + xml_disk += f"" + elif disk_type == 'network': + if pool_type == 'rbd': + auth_type = source_info.get('auth_type') + auth_user = source_info.get('auth_user') + auth_uuid = source_info.get("auth_uuid") + xml_disk += f""" + + """ + xml_disk += f"""""" + for host in source_info.get("hosts"): + if host.get('hostport'): + xml_disk += f"""""" + else: + xml_disk += f"""""" + xml_disk +="""""" + else: + raise Exception("Not implemented disk type") + else: + raise Exception("Not implemented disk type") + + xml_disk +=f"" if readonly or disk_device == "cdrom": xml_disk += """""" if shareable: diff --git a/vrtManager/storage.py b/vrtManager/storage.py index 85eafb0..c7b37f8 100644 --- a/vrtManager/storage.py +++ b/vrtManager/storage.py @@ -145,6 +145,9 @@ class wvmStorage(wvmConnect): def get_target_path(self): return util.get_xml_path(self._XMLDesc(0), "/pool/target/path") + def get_source_name(self): + return util.get_xml_path(self._XMLDesc(0), "/pool/source/name") + def get_allocation(self): return int(util.get_xml_path(self._XMLDesc(0), "/pool/allocation")) @@ -154,6 +157,34 @@ class wvmStorage(wvmConnect): def get_capacity(self): return int(util.get_xml_path(self._XMLDesc(0), "/pool/capacity")) + def get_rbd_source(self): + def hosts(doc): + hosts_array = [] + + for host in doc.xpath("/pool/source/host"): + name = host.get('name') + if name: + port = host.get('port') + if port: + hosts_array.append({"hostname": name, "hostport": port}) + else: + hosts_array.append({"hostname": name}) + + name = doc.get('name') + auth = doc.xpath("/pool/source/auth") + auth_type = auth[0].get("type") + auth_user = auth[0].get("username") + auth_uuid = auth[0].xpath("secret/@uuid")[0] + + return({ + "name": name, + "auth_type": auth_type, + "auth_user": auth_user, + "auth_uuid": auth_uuid, + "hosts": hosts_array + }) + return util.get_xml_path(self._XMLDesc(0), func=hosts) + def get_pretty_allocation(self): return util.pretty_bytes(self.get_allocation()) @@ -185,10 +216,14 @@ class wvmStorage(wvmConnect): vol = self.pool.storageVolLookupByName(name) vol.delete(0) - def get_volume_type(self, name): + def get_volume_format_type(self, name): vol_xml = self._vol_XMLDesc(name) return util.get_xml_path(vol_xml, "/volume/target/format/@type") + def get_volume_type(self, name): + vol_xml = self._vol_XMLDesc(name) + return util.get_xml_path(vol_xml, "/volume/@type") + def refresh(self): self.pool.refresh(0) @@ -206,7 +241,7 @@ class wvmStorage(wvmConnect): "name": volname, "size": self.get_volume_size(volname), "allocation": self.get_volume_allocation(volname), - "type": self.get_volume_type(volname), + "type": self.get_volume_format_type(volname), } ) return vol_list @@ -260,7 +295,7 @@ class wvmStorage(wvmConnect): ): vol = self.get_volume(name) if not vol_fmt: - vol_fmt = self.get_volume_type(name) + vol_fmt = self.get_volume_format_type(name) storage_type = self.get_type() if storage_type == "dir": From a33283e172759abee96bf99419bedc1d1b71a2c9 Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 16 Dec 2021 11:11:54 +0300 Subject: [PATCH 5/5] update dev/conf requirements --- conf/requirements.txt | 10 +++++----- dev/requirements.txt | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/conf/requirements.txt b/conf/requirements.txt index 11e3b12..8e71559 100644 --- a/conf/requirements.txt +++ b/conf/requirements.txt @@ -1,13 +1,13 @@ -Django==3.2.9 -django_bootstrap5==21.1 +Django==3.2.10 +django_bootstrap5==21.2 django-icons==21.1 django-login-required-middleware==0.7 -django-otp==1.1.1 +django-otp==1.1.3 django-qr-code==2.3.0 gunicorn==20.1.0 libsass==0.21.0 -libvirt-python==7.9.0 -lxml==4.6.4 +libvirt-python==7.10.0 +lxml==4.7.1 qrcode==7.3.1 rwlock==0.0.7 websockify==0.10.0 diff --git a/dev/requirements.txt b/dev/requirements.txt index ea7c65f..350e803 100644 --- a/dev/requirements.txt +++ b/dev/requirements.txt @@ -1,7 +1,7 @@ -r ../conf/requirements.txt -coverage==6.1.2 -django-debug-toolbar==3.2.2 +coverage==6.2 +django-debug-toolbar==3.2.4 pycodestyle==2.8.0 pyflakes==2.4.0 -pylint==2.11.1 +pylint==2.12.2 yapf==0.31.0