From e17fecaef54c1a6f43ad03d386b378cf589d222b Mon Sep 17 00:00:00 2001 From: FroggyFlox Date: Sun, 20 Aug 2023 17:22:55 -0400 Subject: [PATCH 1/7] Migrate to New Middleware style #2662 In Django 1.10, the old `MIDDLEWARE_CLASSES` style was deprecated and we should now use `MIDDLEWARE` setting. This commit includes this move and takes advantage of the new MiddlewareMixin to help provide compatibility for our custom middleware. --- src/rockstor/settings.py | 4 ++-- src/rockstor/storageadmin/middleware.py | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/rockstor/settings.py b/src/rockstor/settings.py index 6d24a5c83..5bb0b414c 100644 --- a/src/rockstor/settings.py +++ b/src/rockstor/settings.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2012 RockStor, Inc. +Copyright (c) 2023 RockStor, Inc. This file is part of RockStor. RockStor is free software; you can redistribute it and/or modify @@ -145,7 +145,7 @@ }, ] -MIDDLEWARE_CLASSES = ( +MIDDLEWARE = ( # New in 1.8, 1.11 newly sets Content-Length header. # 'django.middleware.common.CommonMiddleware', "django.contrib.sessions.middleware.SessionMiddleware", diff --git a/src/rockstor/storageadmin/middleware.py b/src/rockstor/storageadmin/middleware.py index 96e92ffdf..2a397662e 100644 --- a/src/rockstor/storageadmin/middleware.py +++ b/src/rockstor/storageadmin/middleware.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2012-2020 RockStor, Inc. +Copyright (c) 2012-2023 RockStor, Inc. This file is part of RockStor. RockStor is free software; you can redistribute it and/or modify @@ -13,18 +13,19 @@ General Public License for more details. You should have received a copy of the GNU General Public License -along with this program. If not, see . +along with this program. If not, see . """ from system.osi import run_command from django.conf import settings +from django.utils.deprecation import MiddlewareMixin import logging logger = logging.getLogger(__name__) -class ProdExceptionMiddleware(object): +class ProdExceptionMiddleware(MiddlewareMixin): def process_exception(self, request, exception): """just log the exception""" e_msg = ( From f84771e253eb3cf1df9417a2739e66cb58a94c74 Mon Sep 17 00:00:00 2001 From: FroggyFlox Date: Mon, 21 Aug 2023 18:28:11 -0400 Subject: [PATCH 2/7] Use user.is_authenticated as an attribute #2664 Prior to Django 1.10, user.is_authenticated() was a method. Since then, compatibility was ensured but this compatibility will be removed in Django 2.0. This commit thus moves to using the user.is_authenticated attribute instead. --- src/rockstor/storageadmin/views/home.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/rockstor/storageadmin/views/home.py b/src/rockstor/storageadmin/views/home.py index db932a516..3a9fe77ca 100644 --- a/src/rockstor/storageadmin/views/home.py +++ b/src/rockstor/storageadmin/views/home.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2012-2020 RockStor, Inc. +Copyright (c) 2012-2023 RockStor, Inc. This file is part of RockStor. RockStor is free software; you can redistribute it and/or modify @@ -13,7 +13,7 @@ General Public License for more details. You should have received a copy of the GNU General Public License -along with this program. If not, see . +along with this program. If not, see . """ from django.shortcuts import render @@ -28,6 +28,7 @@ logger = logging.getLogger(__name__) + def login_page(request): return render(request, "login.html") @@ -65,7 +66,7 @@ def home(request): "update_channel": update_channel, } logger.debug("context={}".format(context)) - if request.user.is_authenticated(): + if request.user.is_authenticated: logger.debug("ABOUT TO RENDER INDEX") return render(request, "index.html", context) else: From 52f428cb00b837acd711643aa988aa8b74c4a996 Mon Sep 17 00:00:00 2001 From: FroggyFlox Date: Wed, 30 Aug 2023 15:08:02 -0400 Subject: [PATCH 3/7] Set `Meta.base_manager_name` on 'storageadmin.Disk' #2666 --- src/rockstor/storageadmin/models/disk.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rockstor/storageadmin/models/disk.py b/src/rockstor/storageadmin/models/disk.py index a699bc798..f6164b344 100644 --- a/src/rockstor/storageadmin/models/disk.py +++ b/src/rockstor/storageadmin/models/disk.py @@ -31,8 +31,6 @@ class AttachedManager(models.Manager): """Manager subclass to return only attached disks""" - use_for_related_fields = True - def attached(self): # Return default queryset after excluding name="detached-*" items. # Alternative lookup type __regex=r'^detached-' @@ -151,3 +149,4 @@ def target_name(self, *args, **kwargs): class Meta: app_label = "storageadmin" + base_manager_name = "attached" From a6e61873bebdec8dad856e087e09001499efa8f1 Mon Sep 17 00:00:00 2001 From: Hooverdan96 <35113775+Hooverdan96@users.noreply.github.com> Date: Mon, 4 Sep 2023 15:56:54 -0700 Subject: [PATCH 4/7] surface Distro Version to breadcrumb bar Fixes #2668. --- src/rockstor/storageadmin/static/storageadmin/js/router.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/rockstor/storageadmin/static/storageadmin/js/router.js b/src/rockstor/storageadmin/static/storageadmin/js/router.js index 8486b9412..efd011a55 100644 --- a/src/rockstor/storageadmin/static/storageadmin/js/router.js +++ b/src/rockstor/storageadmin/static/storageadmin/js/router.js @@ -979,8 +979,7 @@ $(document).ready(function() { }; var distroInfo = function(data) { - $('#distro-info').text("Uses " + data.distro); - $('#distro-info').attr('title', data.version); + $('#distro-info').text("Uses " + data.distro + ": " + data.version); }; var displayLocaleTime = function(data) { From 7b1057ca5937f8713028c6e680c3b21dca81c385 Mon Sep 17 00:00:00 2001 From: FroggyFlox Date: Tue, 12 Sep 2023 10:01:17 -0400 Subject: [PATCH 5/7] Explicitly set REALM when querying workgroup #2671 During Active Directory activation, we query the Workgroup information from the AD server using `net ads workgroup`. This normally gets its parameters from `smb.conf` but we need here to explicitly give the required server information at the command call given we usually work with an empty `smb.conf` file at this stage. This commit switches from using the `-S|--server` flag to the `--realm` flag as that has proven more robust. --- src/rockstor/system/directory_services.py | 25 ++++++++----------- .../system/tests/test_directory_services.py | 11 ++++---- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/src/rockstor/system/directory_services.py b/src/rockstor/system/directory_services.py index 1bca3cfab..9f6d17911 100644 --- a/src/rockstor/system/directory_services.py +++ b/src/rockstor/system/directory_services.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2012-2021 RockStor, Inc. +Copyright (c) 2012-2023 RockStor, Inc. This file is part of RockStor. RockStor is free software; you can redistribute it and/or modify @@ -13,7 +13,7 @@ General Public License for more details. You should have received a copy of the GNU General Public License -along with this program. If not, see . +along with this program. If not, see . """ import os @@ -295,7 +295,7 @@ def leave_domain(config, method="sssd"): run_command(cmd, log=True) -def domain_workgroup(domain=None, method="sssd"): +def domain_workgroup(domain: str, method: str = "sssd") -> str: """ Fetches the Workgroup value from an Active Directory domain to be fed to Samba configuration. @@ -303,20 +303,17 @@ def domain_workgroup(domain=None, method="sssd"): :param method: String - SSSD or Winbind (default is sssd) :return: """ - cmd = [NET, "ads", "workgroup", "-S", domain] - if method == "winbind": - cmd = [ADCLI, "info", domain] - o, e, rc = run_command(cmd) + cmd = [NET, "ads", "workgroup", f"--realm={domain.upper()}"] match_str = "Workgroup:" if method == "winbind": + cmd = [ADCLI, "info", domain] match_str = "domain-short = " - for l in o: - l = l.strip() - if re.match(match_str, l) is not None: - return l.split(match_str)[1].strip() - raise Exception( - "Failed to retrieve Workgroup. out: {} err: {} rc: {}".format(o, e, rc) - ) + o, e, rc = run_command(cmd, log=True) + for line in o: + line = line.strip() + if re.match(match_str, line) is not None: + return line.split(match_str)[1].strip() + raise Exception(f"Failed to retrieve Workgroup. out: {o} err: {e} rc: {rc}") def validate_idmap_range(config): diff --git a/src/rockstor/system/tests/test_directory_services.py b/src/rockstor/system/tests/test_directory_services.py index 2111975ba..a65c6463a 100644 --- a/src/rockstor/system/tests/test_directory_services.py +++ b/src/rockstor/system/tests/test_directory_services.py @@ -22,8 +22,9 @@ class SystemDirectoryServicesTests(unittest.TestCase): """ The tests in this suite can be run via the following command: - cd - ./bin/test --settings=test-settings -v 3 -p test_directory_services* + cd /opt/rockstor/src/rockstor + export DJANGO_SETTINGS_MODULE=settings + poetry run django-admin test -p test_directory_services.py -v 2 """ def setUp(self): @@ -50,8 +51,8 @@ def test_domain_workgroup(self): returned, expected, msg="Un-expected domain_workgroup() result:\n " - "returned = ({}).\n " - "expected = ({}).".format(returned, expected), + f"returned = {returned}.\n " + f"expected = {expected}.", ) def test_domain_workgroup_invalid(self): @@ -62,7 +63,7 @@ def test_domain_workgroup_invalid(self): domain = "bogusad.bogusdomain.com" self.mock_run_command.side_effect = CommandException( err=["Didn't find the cldap server!", ""], - cmd=["/usr/bin/net", "ads", "workgroup", "-S", domain], + cmd=["/usr/bin/net", "ads", "workgroup", f"--realm={domain.upper()}"], out=[""], rc=255, ) From c997dcd62293014662c14c357d3af8f2104bd3a3 Mon Sep 17 00:00:00 2001 From: FroggyFlox Date: Wed, 13 Sep 2023 19:33:54 -0400 Subject: [PATCH 6/7] Catch DBusException to not throw error on LDAP group lookup #2673 We currently use InfoPipe to fetch the groupname of domain users. While this works for Active Directory users, this can fail for LDAP users if these do not belong to a posixAccount group. This commit simply catches the DBusException thrown in such cases and logs the event (DEBUG level). The result is a groupname of "null". Also includes: - minor Black formatting - type hints - import optimization - minor copyright updates --- src/rockstor/system/users.py | 62 ++++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/src/rockstor/system/users.py b/src/rockstor/system/users.py index 1f44b83d0..b5f81dc89 100644 --- a/src/rockstor/system/users.py +++ b/src/rockstor/system/users.py @@ -1,5 +1,5 @@ """ -Copyright (c) 2012-2023 RockStor, Inc. +Copyright (c) 2012-2023 RockStor, Inc. This file is part of RockStor. RockStor is free software; you can redistribute it and/or modify @@ -13,21 +13,21 @@ General Public License for more details. You should have received a copy of the GNU General Public License -along with this program. If not, see . +along with this program. If not, see . """ import crypt -import grp import logging import os import pwd import re import stat -from subprocess import run, Popen, PIPE from shutil import move +from subprocess import run, Popen, PIPE from tempfile import mkstemp +from typing import Union, Optional, Dict, Any import dbus -from dbus import DBusException +import grp from system.exceptions import CommandException from system.osi import run_command @@ -126,7 +126,8 @@ def get_groups(*gids): for ifp_gp, ifp_gid in ifp_groups.items(): if ifp_gp not in groups: groups[ifp_gp] = ifp_gid - except DBusException: + except dbus.DBusException as e: + logger.debug(f"Exception while getting groups from InfoPipe: {e}") pass return groups @@ -284,7 +285,9 @@ def add_ssh_key(username, key, old_key=None): run_command([CHOWN, "%s:%s" % (username, groupname), AUTH_KEYS]) -def ifp_get_properties_from_name_or_id(iface_type, target, *obj_properties): +def ifp_get_properties_from_name_or_id( + iface_type: str, target: Union[str, int], *obj_properties: str +) -> Optional[Dict[str, Any]]: """Get user of group properties from InfoPipe Uses InfoPipe (SSSD D-Bus responder) to get desired properties @@ -299,29 +302,34 @@ def ifp_get_properties_from_name_or_id(iface_type, target, *obj_properties): # InfoPipe depends on the sssd service running: if not is_systemd_service_active("sssd"): return None - bus = dbus.SystemBus() - ifp_bus_name = "org.freedesktop.sssd.infopipe" - - ifp_obj = bus.get_object(ifp_bus_name, IFP_CONSTANTS[iface_type]["obj_path"]) - ifp_iface = dbus.Interface(ifp_obj, IFP_CONSTANTS[iface_type]["main_iface"]) - - if isinstance(target, str): - my_obj = bus.get_object(ifp_bus_name, ifp_iface.FindByName(target)) - elif isinstance(target, int): - my_obj = bus.get_object(ifp_bus_name, ifp_iface.FindByID(target)) - else: - raise Exception( - "Incompatible type for target {}: {}.".format(target, type(target)) - ) + try: + bus = dbus.SystemBus() + ifp_bus_name = "org.freedesktop.sssd.infopipe" + ifp_obj = bus.get_object(ifp_bus_name, IFP_CONSTANTS[iface_type]["obj_path"]) + ifp_iface = dbus.Interface(ifp_obj, IFP_CONSTANTS[iface_type]["main_iface"]) + + if isinstance(target, str): + my_obj = bus.get_object(ifp_bus_name, ifp_iface.FindByName(target)) + elif isinstance(target, int): + my_obj = bus.get_object(ifp_bus_name, ifp_iface.FindByID(target)) + else: + raise Exception( + "Incompatible type for target {}: {}.".format(target, type(target)) + ) - my_iface_properties = dbus.Interface(my_obj, "org.freedesktop.DBus.Properties") + my_iface_properties = dbus.Interface(my_obj, "org.freedesktop.DBus.Properties") - ifp_res = {} - for obj_property in obj_properties: - ifp_res[obj_property] = my_iface_properties.Get( - IFP_CONSTANTS[iface_type]["sub_iface"], obj_property + ifp_res = {} + for obj_property in obj_properties: + ifp_res[obj_property] = my_iface_properties.Get( + IFP_CONSTANTS[iface_type]["sub_iface"], obj_property + ) + return ifp_res + except dbus.DBusException as e: + logger.debug( + f"Exception while getting {obj_properties} for {target} on {iface_type}: {e}" ) - return ifp_res + return None def ifp_get_groups(): From 157344ddfa46cac32622af20df4e76fedc5fe9e0 Mon Sep 17 00:00:00 2001 From: Philip Guyton Date: Fri, 15 Sep 2023 16:10:05 +0100 Subject: [PATCH 7/7] Bump versions to a 5.0.4 base (Testing) - testing branch #2675 pyproject.toml build.sh --- build.sh | 2 +- pyproject.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build.sh b/build.sh index ce9bc57df..1095d6b4c 100644 --- a/build.sh +++ b/build.sh @@ -28,7 +28,7 @@ echo # Add js libs. See: https://github.com/rockstor/rockstor-jslibs # Set jslibs_version of GitHub release: -jslibs_version=5.0.3 +jslibs_version=5.0.4 jslibs_url=https://github.com/rockstor/rockstor-jslibs/archive/refs/tags/"${jslibs_version}".tar.gz # Check for rpm embedded, or previously downloaded jslibs. diff --git a/pyproject.toml b/pyproject.toml index de0a1e786..0e882c646 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api" [tool.poetry] name = "rockstor" -version = "5.0.3" +version = "5.0.4" description = "Btrfs Network Attached Storage (NAS) Appliance." homepage = "https://rockstor.com/" repository = "https://github.com/rockstor/rockstor-core"