From 710d6ef295eaf47773fba5d29f79b32cf4de6d4e Mon Sep 17 00:00:00 2001 From: tong_1001 Date: Tue, 11 May 2021 19:51:01 +0800 Subject: [PATCH] add openEuler policy and fix exception in plugin method "yum.collect()" --- ...-exception-raise-in-Plugin._copy_dir.patch | 30 ++ ...Policies-Plugins-Add-services-member.patch | 284 ++++++++++++++++++ ...ive-Dont-copystat-sys-and-proc-paths.patch | 46 +++ ...-follow-up-to-FileCacheArchive.add_l.patch | 85 ++++++ ...rt-archive-fix-leading-path-creation.patch | 122 ++++++++ ...al-variable-name-in-FileCacheArchive.patch | 30 ++ ...e-dest_dir-in-FileCacheArchive._chec.patch | 34 +++ ...nused-copy-arg-from-FileCacheArchive.patch | 28 ++ ...e-replace-FileCacheArchive._makedirs.patch | 143 +++++++++ ...e-simplify-FileCacheArchive.makedirs.patch | 42 +++ backport-policies-sanitize-report-label.patch | 52 ++++ openEuler-add-openEuler-policy.patch | 49 +++ sos.spec | 18 +- 13 files changed, 962 insertions(+), 1 deletion(-) create mode 100644 backport-Plugin-fix-exception-raise-in-Plugin._copy_dir.patch create mode 100644 backport-Policies-Plugins-Add-services-member.patch create mode 100644 backport-archive-Dont-copystat-sys-and-proc-paths.patch create mode 100644 backport-archive-add-link-follow-up-to-FileCacheArchive.add_l.patch create mode 100644 backport-archive-fix-leading-path-creation.patch create mode 100644 backport-archive-fix-local-variable-name-in-FileCacheArchive.patch create mode 100644 backport-archive-normalise-dest_dir-in-FileCacheArchive._chec.patch create mode 100644 backport-archive-remove-unused-copy-arg-from-FileCacheArchive.patch create mode 100644 backport-archive-replace-FileCacheArchive._makedirs.patch create mode 100644 backport-archive-simplify-FileCacheArchive.makedirs.patch create mode 100644 backport-policies-sanitize-report-label.patch create mode 100644 openEuler-add-openEuler-policy.patch diff --git a/backport-Plugin-fix-exception-raise-in-Plugin._copy_dir.patch b/backport-Plugin-fix-exception-raise-in-Plugin._copy_dir.patch new file mode 100644 index 0000000..00c709d --- /dev/null +++ b/backport-Plugin-fix-exception-raise-in-Plugin._copy_dir.patch @@ -0,0 +1,30 @@ +From 0ea62d1ea57f41c1b75ccb83e69fdda386a7d280 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Fri, 7 Sep 2018 13:00:52 -0400 +Subject: [PATCH 0045/1146] [Plugin] fix exception raise in Plugin._copy_dir() + +Use a naked 'raise' statement rather than raising the already caught +exception in _copy_dir(), so that the original stack and backtrace +are avaialable. + +Signed-off-by: Bryn M. Reeves +--- + sos/plugins/__init__.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py +index 252de4d0..ac2c0bc8 100644 +--- a/sos/plugins/__init__.py ++++ b/sos/plugins/__init__.py +@@ -401,7 +401,7 @@ class Plugin(object): + msg = "Too many levels of symbolic links copying" + self._log_error("_copy_dir: %s '%s'" % (msg, srcpath)) + return +- raise e ++ raise + + def _get_dest_for_srcpath(self, srcpath): + if self.use_sysroot(): +-- +2.26.0.windows.1 + diff --git a/backport-Policies-Plugins-Add-services-member.patch b/backport-Policies-Plugins-Add-services-member.patch new file mode 100644 index 0000000..c86b2a9 --- /dev/null +++ b/backport-Policies-Plugins-Add-services-member.patch @@ -0,0 +1,284 @@ +From 6db459e2b21a798d93cc79e705e8e02f1bbd24c1 Mon Sep 17 00:00:00 2001 +From: Jake Hunsaker +Date: Tue, 24 Jul 2018 17:40:25 -0400 +Subject: [PATCH 0033/1146] [Policies|Plugins] Add services member + +Adds a services member to facilitate plugin enablement. This is tied to +a new InitSystem class that gets attached to policies. The InitSystem +class is used to determine services that are present on the system and +what those service statuses currently are (e.g. enabled/disable). + +Plugins can now specify a set of services to enable the plugin on if +that service exists on the system, similar to the file, command, and +package checks. + +Additionally, the Plugin class now has methods to check on service +states, and make decisions based off of. For example: + + def setup(self): + if self.is_service('foobar'): + self.add_cmd_output('barfoo') + +Currently, only systemd has actual functionality for this. The base +InitSystem inherited by policies by default will always return False for +service checks, thus resulting in the same behavior as before this +change. + +The Red Hat family of distributions has been set to systemd, as all +current versions of those distributions use systemd. + +Closes: #83 +Resolves: #1387 + +Signed-off-by: Jake Hunsaker +Signed-off-by: Bryn M. Reeves +--- + sos/plugins/__init__.py | 31 +++++++++-- + sos/policies/__init__.py | 115 ++++++++++++++++++++++++++++++++++++++- + sos/policies/redhat.py | 1 + + 3 files changed, 142 insertions(+), 5 deletions(-) + +diff --git a/sos/plugins/__init__.py b/sos/plugins/__init__.py +index 82fef18e..252de4d0 100644 +--- a/sos/plugins/__init__.py ++++ b/sos/plugins/__init__.py +@@ -123,6 +123,7 @@ class Plugin(object): + files = () + commands = () + kernel_mods = () ++ services = () + archive = None + profiles = () + sysroot = '/' +@@ -202,6 +203,22 @@ class Plugin(object): + '''Is the package $package_name installed?''' + return self.policy.pkg_by_name(package_name) is not None + ++ def is_service(self, name): ++ '''Does the service $name exist on the system?''' ++ return self.policy.init_system.is_service(name) ++ ++ def service_is_enabled(self, name): ++ '''Is the service $name enabled?''' ++ return self.policy.init_system.is_enabled(name) ++ ++ def service_is_disabled(self, name): ++ '''Is the service $name disabled?''' ++ return self.policy.init_system.is_disabled(name) ++ ++ def get_service_status(self, name): ++ '''Return the reported status for service $name''' ++ return self.policy.init_system.get_service_status(name) ++ + def do_cmd_private_sub(self, cmd): + '''Remove certificate and key output archived by sosreport. cmd + is the command name from which output is collected (i.e. exlcuding +@@ -977,7 +994,8 @@ class Plugin(object): + overridden. + """ + # some files or packages have been specified for this package +- if any([self.files, self.packages, self.commands, self.kernel_mods]): ++ if any([self.files, self.packages, self.commands, self.kernel_mods, ++ self.services]): + if isinstance(self.files, six.string_types): + self.files = [self.files] + +@@ -990,6 +1008,9 @@ class Plugin(object): + if isinstance(self.kernel_mods, six.string_types): + self.kernel_mods = [self.kernel_mods] + ++ if isinstance(self.services, six.string_types): ++ self.services = [self.services] ++ + if isinstance(self, SCLPlugin): + # save SCLs that match files or packages + type(self)._scls_matched = [] +@@ -1005,7 +1026,8 @@ class Plugin(object): + + return self._files_pkgs_or_cmds_present(self.files, + self.packages, +- self.commands) ++ self.commands, ++ self.services) + + if isinstance(self, SCLPlugin): + # if files and packages weren't specified, we take all SCLs +@@ -1013,7 +1035,7 @@ class Plugin(object): + + return True + +- def _files_pkgs_or_cmds_present(self, files, packages, commands): ++ def _files_pkgs_or_cmds_present(self, files, packages, commands, services): + kernel_mods = self.policy.lsmod() + + def have_kmod(kmod): +@@ -1022,7 +1044,8 @@ class Plugin(object): + return (any(os.path.exists(fname) for fname in files) or + any(self.is_installed(pkg) for pkg in packages) or + any(is_executable(cmd) for cmd in commands) or +- any(have_kmod(kmod) for kmod in self.kernel_mods)) ++ any(have_kmod(kmod) for kmod in self.kernel_mods) or ++ any(self.is_service(svc) for svc in services)) + + def default_enabled(self): + """This decides whether a plugin should be automatically loaded or +diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py +index 65d8aac6..d6255d3e 100644 +--- a/sos/policies/__init__.py ++++ b/sos/policies/__init__.py +@@ -13,7 +13,8 @@ from os import environ + + from sos.utilities import (ImporterHelper, + import_module, +- shell_out) ++ shell_out, ++ sos_get_command_output) + from sos.plugins import IndependentPlugin, ExperimentalPlugin + from sos import _sos as _ + from sos import SoSOptions, _arg_names +@@ -49,6 +50,113 @@ def load(cache={}, sysroot=None): + return cache['policy'] + + ++class InitSystem(object): ++ """Encapsulates an init system to provide service-oriented functions to ++ sos. ++ ++ This should be used to query the status of services, such as if they are ++ enabled or disabled on boot, or if the service is currently running. ++ """ ++ ++ def __init__(self, init_cmd=None, list_cmd=None, query_cmd=None): ++ ++ self.services = {} ++ ++ self.init_cmd = init_cmd ++ self.list_cmd = "%s %s" % (self.init_cmd, list_cmd) or None ++ self.query_cmd = "%s %s" % (self.init_cmd, query_cmd) or None ++ ++ self.load_all_services() ++ ++ def is_enabled(self, name): ++ """Check if given service name is enabled """ ++ if self.services and name in self.services: ++ return self.services[name]['config'] == 'enabled' ++ return False ++ ++ def is_disabled(self, name): ++ """Check if a given service name is disabled """ ++ if self.services and name in self.services: ++ return self.services[name]['config'] == 'disabled' ++ return False ++ ++ def is_service(self, name): ++ """Checks if the given service name exists on the system at all, this ++ does not check for the service status ++ """ ++ return name in self.services ++ ++ def load_all_services(self): ++ """This loads all services known to the init system into a dict. ++ The dict should be keyed by the service name, and contain a dict of the ++ name and service status ++ """ ++ pass ++ ++ def _query_service(self, name): ++ """Query an individual service""" ++ if self.query_cmd: ++ res = sos_get_command_output("%s %s" % (self.query_cmd, name)) ++ if res['status'] == 0: ++ return res ++ else: ++ return None ++ return None ++ ++ def parse_query(self, output): ++ """Parses the output returned by the query command to make a ++ determination of what the state of the service is ++ ++ This should be overriden by anything that subclasses InitSystem ++ """ ++ return output ++ ++ def get_service_status(self, name): ++ """Returns the status for the given service name along with the output ++ of the query command ++ """ ++ svc = self._query_service(name) ++ if svc is not None: ++ return {'name': name, ++ 'status': self.parse_query(svc['output']), ++ 'output': svc['output'] ++ } ++ else: ++ return {'name': name, ++ 'status': 'missing', ++ 'output': '' ++ } ++ ++ ++class SystemdInit(InitSystem): ++ ++ def __init__(self): ++ super(SystemdInit, self).__init__( ++ init_cmd='systemctl', ++ list_cmd='list-unit-files --type=service', ++ query_cmd='status' ++ ) ++ ++ def parse_query(self, output): ++ for line in output.splitlines(): ++ if line.strip().startswith('Active:'): ++ return line.split()[1] ++ return 'unknown' ++ ++ def load_all_services(self): ++ svcs = shell_out(self.list_cmd).splitlines() ++ for line in svcs: ++ try: ++ name = line.split('.service')[0] ++ config = line.split()[1] ++ self.services[name] = { ++ 'name': name, ++ 'config': config ++ } ++ except IndexError: ++ pass ++ ++ + class PackageManager(object): + """Encapsulates a package manager. If you provide a query_command to the + constructor it should print each package on the system in the following +@@ -676,11 +784,16 @@ class LinuxPolicy(Policy): + distro = "Linux" + vendor = "None" + PATH = "/bin:/sbin:/usr/bin:/usr/sbin" ++ init = None + + _preferred_hash_name = None + + def __init__(self, sysroot=None): + super(LinuxPolicy, self).__init__(sysroot=sysroot) ++ if self.init == 'systemd': ++ self.init_system = SystemdInit() ++ else: ++ self.init_system = InitSystem() + + def get_preferred_hash_name(self): + +diff --git a/sos/policies/redhat.py b/sos/policies/redhat.py +index 5bfbade2..b494de3c 100644 +--- a/sos/policies/redhat.py ++++ b/sos/policies/redhat.py +@@ -45,6 +45,7 @@ class RedHatPolicy(LinuxPolicy): + _host_sysroot = '/' + default_scl_prefix = '/opt/rh' + name_pattern = 'friendly' ++ init = 'systemd' + + def __init__(self, sysroot=None): + super(RedHatPolicy, self).__init__(sysroot=sysroot) +-- +2.26.0.windows.1 + diff --git a/backport-archive-Dont-copystat-sys-and-proc-paths.patch b/backport-archive-Dont-copystat-sys-and-proc-paths.patch new file mode 100644 index 0000000..44040c5 --- /dev/null +++ b/backport-archive-Dont-copystat-sys-and-proc-paths.patch @@ -0,0 +1,46 @@ +From d5b1d349b868e66a4001c23dae7afa05daaca907 Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Wed, 22 Aug 2018 10:35:58 +0200 +Subject: [PATCH 0022/1146] [archive] Dont copystat /sys and /proc paths + +Stop copying extended attributes of files under /sys and /proc +that can raise SELinux denials on that attempt. + +Resolves: #1399 + +Signed-off-by: Pavel Moravec +--- + sos/archive.py | 13 +++++++------ + 1 file changed, 7 insertions(+), 6 deletions(-) + +diff --git a/sos/archive.py b/sos/archive.py +index fdf6f9a8..5d99170f 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -251,16 +251,17 @@ class FileCacheArchive(Archive): + pass + else: + self.log_info("caught '%s' copying '%s'" % (e, src)) +- try: +- shutil.copystat(src, dest) +- except OSError: +- # SELinux xattrs in /proc and /sys throw this +- pass ++ # copy file attributes, skip SELinux xattrs for /sys and /proc + try: + stat = os.stat(src) ++ if src.startswith("/sys/") or src.startswith("/proc/"): ++ shutil.copymode(src, dest) ++ os.utime(dest, ns=(stat.st_atime_ns, stat.st_mtime_ns)) ++ else: ++ shutil.copystat(src, dest) + os.chown(dest, stat.st_uid, stat.st_gid) + except Exception as e: +- self.log_debug("caught '%s' setting ownership of '%s'" ++ self.log_debug("caught '%s' setting attributes of '%s'" + % (e, dest)) + file_name = "'%s'" % src + else: +-- +2.26.0.windows.1 + diff --git a/backport-archive-add-link-follow-up-to-FileCacheArchive.add_l.patch b/backport-archive-add-link-follow-up-to-FileCacheArchive.add_l.patch new file mode 100644 index 0000000..4977c3d --- /dev/null +++ b/backport-archive-add-link-follow-up-to-FileCacheArchive.add_l.patch @@ -0,0 +1,85 @@ +From 322f4a517ae336cc1443f9a399a0d15d45ec48b9 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Fri, 7 Sep 2018 13:11:03 -0400 +Subject: [PATCH 0047/1146] [archive] add link follow-up to + FileCacheArchive.add_link() + +Creating a link may trigger further actions in the archive: if the +link target is a regular file, we must copy that file into the +archive, and if the target is a symbolic link, then we must create +that link, and copy in the link target. + +Handle this by calling add_file() or (recursively) add_link() in +order to create the missing pieces of the symlink chain. + +These operations must take place outside of the path lock since +they do not modify the archive namespace and will call methods of +the Archive object that will attempt to re-acquire this lock. + +Resolves: #1404 + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 38 +++++++++++++++++++++++++++++++++++--- + 1 file changed, 35 insertions(+), 3 deletions(-) + +diff --git a/sos/archive.py b/sos/archive.py +index c256a01f..6db398fc 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -403,6 +403,7 @@ class FileCacheArchive(Archive): + % (dest, self._archive_root)) + + def add_link(self, source, link_name): ++ self.log_debug("adding symlink at '%s' -> '%s'" % (link_name, source)) + with self._path_lock: + dest = self._check_path(link_name, P_LINK) + if not dest: +@@ -410,10 +411,41 @@ class FileCacheArchive(Archive): + + if not os.path.lexists(dest): + os.symlink(source, dest) +- self.log_debug("added symlink at '%s' to '%s' in archive '%s'" +- % (dest, source, self._archive_root)) ++ self.log_debug("added symlink at '%s' to '%s' in archive '%s'" ++ % (dest, source, self._archive_root)) ++ ++ # Follow-up must be outside the path lock: we recurse into ++ # other monitor methods that will attempt to reacquire it. ++ ++ source_dir = os.path.dirname(link_name) ++ host_source = os.path.join(source_dir, source) ++ if not os.path.exists(self.dest_path(host_source)): ++ if os.path.islink(host_source): ++ link_dir = os.path.dirname(link_name) ++ link_name = os.path.normpath(os.path.join(link_dir, source)) ++ dest_dir = os.path.dirname(link_name) ++ source = os.path.join(dest_dir, os.readlink(link_name)) ++ source = os.path.relpath(source) ++ self.log_debug("Adding link %s -> %s for link follow up" % ++ (link_name, source)) ++ self.add_link(source, link_path) ++ elif os.path.isdir(host_source): ++ self.log_debug("Adding dir %s for link follow up" % source) ++ self.add_dir(host_source) ++ elif os.path.isfile(host_source): ++ self.log_debug("Adding file %s for link follow up" % source) ++ self.add_file(host_source) ++ else: ++ self.log_debug("No link follow up: source=%s link_name=%s" % ++ (source, link_name)) + +- def add_dir(self, path): ++ ++ def add_dir(self, path, copy=False): ++ """Create a directory in the archive. ++ ++ :param path: the path in the host file system to add ++ """ ++ # Establish path structure + with self._path_lock: + self._check_path(path, P_DIR) + +-- +2.26.0.windows.1 + diff --git a/backport-archive-fix-leading-path-creation.patch b/backport-archive-fix-leading-path-creation.patch new file mode 100644 index 0000000..56e0cc4 --- /dev/null +++ b/backport-archive-fix-leading-path-creation.patch @@ -0,0 +1,122 @@ +From d84c1cd6dedf51a8ed7b1a511585c0ac2db0f083 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Wed, 5 Sep 2018 12:46:16 +0100 +Subject: [PATCH 0046/1146] [archive] fix leading path creation + +Fix the creation of leading path components for both paths that +contain intermediate components that are symbolic links (with both +absolute and relative targets), and those that contain only +directory components. + +Since symlinks may link to other files, and other symlinks, it is +necessary to handle these paths recursively and to include any +intermediate symlinked directories, or symlink targets in the set +of paths added to the archive. + +Related: #1404 + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 41 ++++++++++++++++++++++++++++++++++------- + 1 file changed, 34 insertions(+), 7 deletions(-) + +diff --git a/sos/archive.py b/sos/archive.py +index 473af86..47c80c3 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -164,9 +164,24 @@ class FileCacheArchive(Archive): + The standard python `os.makedirs` is insufficient for our + needs: it will only create directories, and ignores the fact + that some path components may be symbolic links. ++ ++ :param src: The source path in the host file system for which ++ leading components should be created, or the path ++ to an sos_* virtual directory inside the archive. ++ ++ Host paths must be absolute (initial '/'), and ++ sos_* directory paths must be a path relative to ++ the root of the archive. ++ ++ :param mode: An optional mode to be used when creating path ++ components. ++ :returns: A rewritten destination path in the case that one ++ or more symbolic links in intermediate components ++ of the path have altered the path destination. + """ + self.log_debug("Making leading paths for %s" % src) + root = self._archive_root ++ dest = src + + def in_archive(path): + """Test whether path ``path`` is inside the archive. +@@ -190,34 +205,42 @@ class FileCacheArchive(Archive): + path_comps.reverse() + + abs_path = root +- rel_path = "" ++ src_path = "/" + + # Check and create components as needed + for comp in path_comps: + abs_path = os.path.join(abs_path, comp) + ++ # Do not create components that are above the archive root. + if not in_archive(abs_path): + continue + +- rel_path = os.path.join(rel_path, comp) +- src_path = os.path.join("/", rel_path) ++ src_path = os.path.join(src_path, comp) + + if not os.path.exists(abs_path): + self.log_debug("Making path %s" % abs_path) + if os.path.islink(src_path) and os.path.isdir(src_path): + target = os.readlink(src_path) +- abs_target = os.path.join(root, target) ++ ++ # The directory containing the source in the host fs, ++ # adjusted for the current level of path creation. ++ target_dir = os.path.split(src_path)[0] ++ ++ # The source path of the target in the host fs to be ++ # recursively copied. ++ target_src = os.path.join(target_dir, target) + + # Recursively create leading components of target +- self._make_leading_paths(abs_target, mode=mode) ++ dest = self._make_leading_paths(target_src, mode=mode) ++ dest = os.path.normpath(dest) + + self.log_debug("Making symlink '%s' -> '%s'" % + (abs_path, target)) +- target = os.path.relpath(target) + os.symlink(target, abs_path) + else: + self.log_debug("Making directory %s" % abs_path) + os.mkdir(abs_path, mode) ++ return dest + + def _check_path(self, src, path_type, dest=None): + """Check a new destination path in the archive. +@@ -257,13 +280,17 @@ class FileCacheArchive(Archive): + if not dest_dir: + return dest + ++ # Preserve destination basename for rewritten dest_dir ++ dest_name = os.path.split(src)[1] ++ + # Check containing directory presence and path type + if os.path.exists(dest_dir) and not os.path.isdir(dest_dir): + raise ValueError("path '%s' exists and is not a directory" % + dest_dir) + elif not os.path.exists(dest_dir): + src_dir = src if path_type == P_DIR else os.path.split(src)[0] +- self._make_leading_paths(src_dir) ++ src_dir = self._make_leading_paths(src_dir) ++ dest = self.dest_path(os.path.join(src_dir, dest_name)) + + def is_special(mode): + return any([ +-- +2.13.7 + diff --git a/backport-archive-fix-local-variable-name-in-FileCacheArchive.patch b/backport-archive-fix-local-variable-name-in-FileCacheArchive.patch new file mode 100644 index 0000000..42bd9b5 --- /dev/null +++ b/backport-archive-fix-local-variable-name-in-FileCacheArchive.patch @@ -0,0 +1,30 @@ +From 3a2453c186084a2b7ef15702775809a76e13c45c Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Tue, 11 Sep 2018 12:54:20 +0100 +Subject: [PATCH 0051/1146] [archive] fix local variable name in + FileCacheArchive.add_link() + +The 'link_path' local was renamed to 'link_name' to better match +other uses in the code. + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/sos/archive.py b/sos/archive.py +index 4b30630b..528cfa57 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -428,7 +428,7 @@ class FileCacheArchive(Archive): + source = os.path.relpath(source) + self.log_debug("Adding link %s -> %s for link follow up" % + (link_name, source)) +- self.add_link(source, link_path) ++ self.add_link(source, link_name) + elif os.path.isdir(host_source): + self.log_debug("Adding dir %s for link follow up" % source) + self.add_dir(host_source) +-- +2.26.0.windows.1 + diff --git a/backport-archive-normalise-dest_dir-in-FileCacheArchive._chec.patch b/backport-archive-normalise-dest_dir-in-FileCacheArchive._chec.patch new file mode 100644 index 0000000..42088b8 --- /dev/null +++ b/backport-archive-normalise-dest_dir-in-FileCacheArchive._chec.patch @@ -0,0 +1,34 @@ +From ca422720b74181b2433473428e29e90af59b3cf8 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Fri, 31 Aug 2018 12:55:51 +0100 +Subject: [PATCH 0025/1146] [archive] normalise dest_dir in + FileCacheArchive._check_path() + +Always set a valid dest_dir in _check_path() and do not assume +that it can be obtained by splitting the path: in the case of +a directory it is the unmodified 'dest' value. + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/sos/archive.py b/sos/archive.py +index ffa54036..903cc672 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -191,7 +191,10 @@ class FileCacheArchive(Archive): + copied now or `None` otherwise + """ + dest = dest or self.dest_path(src) +- dest_dir = os.path.split(dest)[0] ++ if path_type == P_DIR: ++ dest_dir = dest ++ else: ++ dest_dir = os.path.split(dest)[0] + if not dest_dir: + return dest + +-- +2.26.0.windows.1 + diff --git a/backport-archive-remove-unused-copy-arg-from-FileCacheArchive.patch b/backport-archive-remove-unused-copy-arg-from-FileCacheArchive.patch new file mode 100644 index 0000000..9328253 --- /dev/null +++ b/backport-archive-remove-unused-copy-arg-from-FileCacheArchive.patch @@ -0,0 +1,28 @@ +From 6e79c4b4a4f32fa549708dbb8c8b9af73ab8ff61 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Mon, 10 Sep 2018 16:33:33 +0100 +Subject: [PATCH 0048/1146] [archive] remove unused 'copy' arg from + FileCacheArchive.add_dir() + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/sos/archive.py b/sos/archive.py +index 6db398fc..4b30630b 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -439,8 +439,7 @@ class FileCacheArchive(Archive): + self.log_debug("No link follow up: source=%s link_name=%s" % + (source, link_name)) + +- +- def add_dir(self, path, copy=False): ++ def add_dir(self, path): + """Create a directory in the archive. + + :param path: the path in the host file system to add +-- +2.26.0.windows.1 + diff --git a/backport-archive-replace-FileCacheArchive._makedirs.patch b/backport-archive-replace-FileCacheArchive._makedirs.patch new file mode 100644 index 0000000..25456f6 --- /dev/null +++ b/backport-archive-replace-FileCacheArchive._makedirs.patch @@ -0,0 +1,143 @@ +From 75d759066e8ee0a469abc37f48f7bfcdfe8182b5 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Fri, 31 Aug 2018 12:58:01 +0100 +Subject: [PATCH 0026/1146] [archive] replace FileCacheArchive._makedirs() + +The Python os.makedirs() implementation is inadequate for sos's +needs: it will create leading directories given an intended path +destination, but it is not able to reflect cases where some of +the intermediate paths are actually symbolic links. + +Replace the use of os.makedirs() with a method that walks over +the path, and either creates directories, or symbolic links (and +their directory target) to better correspond with the content of +the host file system. + +This fixes a situation where two plugins can race in the archive, +leading to an exception in the plugin that runs last: + + - /foo/bar exists and is a link to /foo/bar.qux + - One plugin attempts to collect /foo/bar + - Another plugin attempts to collect a link /foo/qux -> /foo/bar/baz + +If the 2nd plugin happens to run first it will create the path +"/foo/bar" as a _directory_ (via _makedirs()). Since the archive +now checks for matching object types when a path collision occurs, +the first plugin will arrive at add_dir(), note that "/foo/bar" is +present and is not a symbolic link, and will raise an exception. + +Correct this by ensuring that whichever plugin executes first, the +correct link/directory path structure will be set up. + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 72 +++++++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 64 insertions(+), 8 deletions(-) + +diff --git a/sos/archive.py b/sos/archive.py +index b7af508..473af86 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -158,6 +158,67 @@ class FileCacheArchive(Archive): + name = name.lstrip(os.sep) + return (os.path.join(self._archive_root, name)) + ++ def _make_leading_paths(self, src, mode=0o700): ++ """Create leading path components ++ ++ The standard python `os.makedirs` is insufficient for our ++ needs: it will only create directories, and ignores the fact ++ that some path components may be symbolic links. ++ """ ++ self.log_debug("Making leading paths for %s" % src) ++ root = self._archive_root ++ ++ def in_archive(path): ++ """Test whether path ``path`` is inside the archive. ++ """ ++ return path.startswith(os.path.join(root, "")) ++ ++ if not src.startswith("/"): ++ # Sos archive path (sos_commands, sos_logs etc.) ++ src_dir = src ++ else: ++ # Host file path ++ src_dir = src if os.path.isdir(src) else os.path.split(src)[0] ++ ++ # Build a list of path components in root-to-leaf order. ++ path = src_dir ++ path_comps = [] ++ while path != '/' and path != '': ++ head, tail = os.path.split(path) ++ path_comps.append(tail) ++ path = head ++ path_comps.reverse() ++ ++ abs_path = root ++ rel_path = "" ++ ++ # Check and create components as needed ++ for comp in path_comps: ++ abs_path = os.path.join(abs_path, comp) ++ ++ if not in_archive(abs_path): ++ continue ++ ++ rel_path = os.path.join(rel_path, comp) ++ src_path = os.path.join("/", rel_path) ++ ++ if not os.path.exists(abs_path): ++ self.log_debug("Making path %s" % abs_path) ++ if os.path.islink(src_path) and os.path.isdir(src_path): ++ target = os.readlink(src_path) ++ abs_target = os.path.join(root, target) ++ ++ # Recursively create leading components of target ++ self._make_leading_paths(abs_target, mode=mode) ++ ++ self.log_debug("Making symlink '%s' -> '%s'" % ++ (abs_path, target)) ++ target = os.path.relpath(target) ++ os.symlink(target, abs_path) ++ else: ++ self.log_debug("Making directory %s" % abs_path) ++ os.mkdir(abs_path, mode) ++ + def _check_path(self, src, path_type, dest=None): + """Check a new destination path in the archive. + +@@ -201,7 +262,8 @@ class FileCacheArchive(Archive): + raise ValueError("path '%s' exists and is not a directory" % + dest_dir) + elif not os.path.exists(dest_dir): +- self._makedirs(dest_dir) ++ src_dir = src if path_type == P_DIR else os.path.split(src)[0] ++ self._make_leading_paths(src_dir) + + def is_special(mode): + return any([ +@@ -319,10 +381,7 @@ class FileCacheArchive(Archive): + + def add_dir(self, path): + with self._path_lock: +- dest = self._check_path(path, P_DIR) +- if not dest: +- return +- self.makedirs(path) ++ self._check_path(path, P_DIR) + + def add_node(self, path, mode, device): + dest = self._check_path(path, P_NODE) +@@ -340,9 +399,6 @@ class FileCacheArchive(Archive): + raise e + shutil.copystat(path, dest) + +- def _makedirs(self, path, mode=0o700): +- os.makedirs(path, mode) +- + def name_max(self): + if 'PC_NAME_MAX' in os.pathconf_names: + pc_name_max = os.pathconf_names['PC_NAME_MAX'] +-- +2.13.7 + diff --git a/backport-archive-simplify-FileCacheArchive.makedirs.patch b/backport-archive-simplify-FileCacheArchive.makedirs.patch new file mode 100644 index 0000000..ae03e4b --- /dev/null +++ b/backport-archive-simplify-FileCacheArchive.makedirs.patch @@ -0,0 +1,42 @@ +From c496d2bec8cae175faf986567e73d16d401d8564 Mon Sep 17 00:00:00 2001 +From: "Bryn M. Reeves" +Date: Fri, 31 Aug 2018 12:52:38 +0100 +Subject: [PATCH 0024/1146] [archive] simplify FileCacheArchive.makedirs() + +Simplify the makedirs() method of FileCacheArchive and have it +bypass _check_path() and directly call os.makedirs(): a subsequent +patch will restrict the use of the method to setting up the sos_* +directories in the archive root. + +File, directory and other object type add_* methods will use a +new method that correctly handles symbolic links in intermediate +path components. + +Signed-off-by: Bryn M. Reeves +--- + sos/archive.py | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/sos/archive.py b/sos/archive.py +index 5d99170f..ffa54036 100644 +--- a/sos/archive.py ++++ b/sos/archive.py +@@ -361,11 +361,11 @@ class FileCacheArchive(Archive): + return self._archive_root + + def makedirs(self, path, mode=0o700): +- dest = self._check_path(path, P_DIR) +- if not dest: +- return ++ """Create path, including leading components. + +- self._makedirs(self.dest_path(path)) ++ Used by sos.sosreport to set up sos_* directories. ++ """ ++ os.makedirs(os.path.join(self._archive_root, path), mode=mode) + self.log_debug("created directory at '%s' in FileCacheArchive '%s'" + % (path, self._archive_root)) + +-- +2.26.0.windows.1 + diff --git a/backport-policies-sanitize-report-label.patch b/backport-policies-sanitize-report-label.patch new file mode 100644 index 0000000..fca78a3 --- /dev/null +++ b/backport-policies-sanitize-report-label.patch @@ -0,0 +1,52 @@ +From bc650cd161548159e551ddc201596bf19b1865d0 Mon Sep 17 00:00:00 2001 +From: Pavel Moravec +Date: Fri, 27 Jul 2018 08:56:37 +0200 +Subject: [PATCH 0012/1146] [policies] sanitize report label + +similarly like we sanitize case id, we should sanitize report label +to e.g. exclude spaces from final tarball name. + +Resolves: #1389 + +Signed-off-by: Pavel Moravec +--- + sos/policies/__init__.py | 9 +++------ + 1 file changed, 3 insertions(+), 6 deletions(-) + +diff --git a/sos/policies/__init__.py b/sos/policies/__init__.py +index 7b301dec..65d8aac6 100644 +--- a/sos/policies/__init__.py ++++ b/sos/policies/__init__.py +@@ -408,7 +408,7 @@ No changes will be made to system configuration. + date=date, + rand=rand + ) +- return time.strftime(nstr) ++ return self.sanitize_filename(time.strftime(nstr)) + + # for some specific binaries like "xz", we need to determine package + # providing it; that is policy specific. By default return the binary +@@ -726,8 +726,8 @@ class LinuxPolicy(Policy): + """Returns the name usd in the pre_work step""" + return self.host_name() + +- def sanitize_case_id(self, case_id): +- return re.sub(r"[^-a-z,A-Z.0-9]", "", case_id) ++ def sanitize_filename(self, name): ++ return re.sub(r"[^-a-z,A-Z.0-9]", "", name) + + def lsmod(self): + """Return a list of kernel module names as strings. +@@ -755,9 +755,6 @@ class LinuxPolicy(Policy): + if cmdline_opts.case_id: + self.case_id = cmdline_opts.case_id + +- if self.case_id: +- self.case_id = self.sanitize_case_id(self.case_id) +- + return + + +-- +2.26.0.windows.1 + diff --git a/openEuler-add-openEuler-policy.patch b/openEuler-add-openEuler-policy.patch new file mode 100644 index 0000000..348f2b1 --- /dev/null +++ b/openEuler-add-openEuler-policy.patch @@ -0,0 +1,49 @@ +From 3b76979a51f8b8e65991c00cd4ebab2f23a467a6 Mon Sep 17 00:00:00 2001 +From: shixuantong +Date: Mon, 8 Mar 2021 20:56:05 +0800 +Subject: [PATCH] add openEuler policy + +this patch is based on sos-3.6. +--- + sos/policies/openEuler.py | 29 +++++++++++++++++++++++++++++ + 1 file changed, 29 insertions(+) + create mode 100644 sos/policies/openEuler.py + +diff --git a/sos/policies/openEuler.py b/sos/policies/openEuler.py +new file mode 100644 +index 0000000..0c9b8f3 +--- /dev/null ++++ b/sos/policies/openEuler.py +@@ -0,0 +1,29 @@ ++from __future__ import print_function ++ ++from sos.plugins import RedHatPlugin ++from sos.policies.redhat import RedHatPolicy, OS_RELEASE ++import os ++ ++class OpenEulerPolicy(RedHatPolicy): ++ ++ distro = "OpenEuler" ++ vendor = "the openEuler Project" ++ vendor_url = "https://openeuler.org/" ++ ++ def __init__(self, sysroot=None): ++ super(OpenEulerPolicy, self).__init__(sysroot=sysroot) ++ ++ @classmethod ++ def check(cls): ++ """This method checks to see if we are running on OpenEuler. It returns ++ True or False.""" ++ try: ++ with open("/etc/openEuler-release", "r") as f: ++ return "openEuler" in f.read() ++ except IOError: ++ return False ++ ++ def openEuler_version(self): ++ pkg = self.pkg_by_name("openEuler-release") or \ ++ self.all_pkgs_by_name_regex("openEuler-release-.*")[-1] ++ return int(pkg["version"]) +-- +1.8.3.1 + diff --git a/sos.spec b/sos.spec index 162b508..04e1496 100644 --- a/sos.spec +++ b/sos.spec @@ -2,7 +2,7 @@ Name: sos Version: 3.6 -Release: 5 +Release: 6 Summary: A set of tools to gather troubleshooting information from a system License: GPLv2+ URL: http://github.com/sosreport/sos @@ -13,6 +13,19 @@ Requires: libxml2-python3 bzip2 xz python3-six BuildArch: noarch Patch0: kernel-dont-collect-some-tracing-instance-files.patch +Patch6000: backport-policies-sanitize-report-label.patch +Patch6001: backport-archive-Dont-copystat-sys-and-proc-paths.patch +Patch6002: backport-archive-simplify-FileCacheArchive.makedirs.patch +Patch6003: backport-archive-normalise-dest_dir-in-FileCacheArchive._chec.patch +Patch6004: backport-archive-replace-FileCacheArchive._makedirs.patch +Patch6005: backport-Policies-Plugins-Add-services-member.patch +Patch6006: backport-Plugin-fix-exception-raise-in-Plugin._copy_dir.patch +Patch6007: backport-archive-fix-leading-path-creation.patch +Patch6008: backport-archive-add-link-follow-up-to-FileCacheArchive.add_l.patch +Patch6009: backport-archive-remove-unused-copy-arg-from-FileCacheArchive.patch +Patch6010: backport-archive-fix-local-variable-name-in-FileCacheArchive.patch + +Patch9000: openEuler-add-openEuler-policy.patch %description Sos is an extensible, portable, support data collection tool primarily @@ -46,5 +59,8 @@ install -Dm644 %{name}.conf %{buildroot}%{_sysconfdir}/%{name}.conf %{_mandir}/man5/sos.conf.5.gz %changelog +* Tue May 11 2021 shixuantong - 3.6-6 +- add openEuler policy and fix exception in plugin method "yum.collect()" + * Mon Feb 17 2020 openEuler Buildteam - 3.6-5 - Package init -- Gitee