Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SCLPlugin doesn't work on EL8 and makes plugins using it not auto-load #2407

Closed
evgeni opened this issue Feb 5, 2021 · 5 comments
Closed

Comments

@evgeni
Copy link
Contributor

evgeni commented Feb 5, 2021

Ohai,

we (@theforeman) recently noticed that the foreman plugin is not automatically enabled on EL8 (CentOS8). A bit of digging revealed that this is due to the fact that the plugin does subclass SCLPlugin

sos/sos/plugins/foreman.py

Lines 309 to 316 in 00a25de

class RedHatForeman(Foreman, SCLPlugin, RedHatPlugin):
apachepkg = 'httpd'
def setup(self):
super(RedHatForeman, self).setup()
self.add_cmd_output_scl('tfm', 'gem list',
suggest_filename='scl enable tfm gem list')

And that seems to confuse sos on EL8 as there are no SCL there.

Dropping the SCLPlugin (and the add_cmd_output_scl call) makes sos (sos-3.9.1-6.el8.noarch) auto-enable the plugin as desired when one of the listed packages is installed.

We see the same behavior with the postgresql plugin, which also uses SCLPlugin.

What's the correct solution here? Fixing SCLPlugin not to fail on EL8? Making two foreman plugins (well, three, we already have RedHatForeman and DebianForeman)?

@TurboTurtle
Copy link
Member

I wonder if this is due to the fact that we have:

class RedHatForeman(Foreman, SCLPlugin, RedHatPlugin):

and

class SCLPlugin(RedHatPlugin)

This might be causing an MRO exception during instantiation. If you instead remove RedHatPlugin and leave SCLPlugin, does the plugin load properly on CentOS for you?

@evgeni
Copy link
Contributor Author

evgeni commented Feb 8, 2021

Nope, that's not it. The PostgreSQL plugin doesn't do this double-inheritance from RedHatPlugin:

class RedHatPostgreSQL(PostgreSQL, SCLPlugin):

FWIW, this is rather easily reproducible with a CentOS 8 container:

% podman run -ti --rm centos:8 bash
# yum install -y sos postgresql
# sosreport --profile services --list-plugins | grep PostgreSQL
WARNING: unable to set option for disabled or non-existing plugin (boot)

 postgresql           inactive       PostgreSQL RDBMS

(the --profile services is required, as it's not loaded by default in a container that has no init)

Making the plugin definition be

class RedHatPostgreSQL(PostgreSQL, RedHatPlugin)

makes it work (after importing RedHatPlugin)

@TurboTurtle
Copy link
Member

Right, so here's the logic for enabling plugins based on if an SCL is present:

            if isinstance(self, SCLPlugin):
                # save SCLs that match files or packages
                type(self)._scls_matched = []
                for scl in self._get_scls():
                    files = [f % {"scl_name": scl} for f in self.files]
                    packages = [p % {"scl_name": scl} for p in self.packages]
                    commands = [c % {"scl_name": scl} for c in self.commands]
                    services = [s % {"scl_name": scl} for s in self.services]
                    if self._check_plugin_triggers(files,
                                                   packages,
                                                   commands,
                                                   services):
                        type(self)._scls_matched.append(scl)
                return len(type(self)._scls_matched) > 0

            return self._check_plugin_triggers(self.files,
                                               self.packages,
                                               self.commands,
                                               self.services)

So we don't even attempt to do the plugin verification based on the normal triggers if a plugin subclasses SCLPlugin at all. This may be a hold over of sorts as in the past the SCLPlugin plugins would usually be a separate class definition by themselves.

So, we have two options I believe:

  1. Change the logic above to only return IF we match SCLs, and otherwise let the regular triggers make the enablement decisions.
  2. Break out separate subclasses for SCLPlugin (again?).

The problem with option 1 would be controlling the SCLPlugin methods for when the plugin gets enabled by the normal, non-scl, triggers.

The problem with option 2 is we'd have to come up with a way to determine which class to run if both a RedHatPlugin and SCLPlugin are determined to be enabled.

@TurboTurtle
Copy link
Member

TurboTurtle commented Feb 8, 2021

A quick test for postgresql shows this solves the enablement issue, and for this particular plugin the scl methods don't seem to come into play - or at least they don't generate any errors or unexpected collections.

diff --git a/sos/report/plugins/__init__.py b/sos/report/plugins/__init__.py
index 5ad7e369..24948ed5 100644
--- a/sos/report/plugins/__init__.py
+++ b/sos/report/plugins/__init__.py
@@ -2568,7 +2568,9 @@ class Plugin(object):
                                                    commands,
                                                    services):
                         type(self)._scls_matched.append(scl)
-                return len(type(self)._scls_matched) > 0
+                    if type(self)._scls_matched:
+                        return True
 
             return self._check_plugin_triggers(self.files,
                                                self.packages,

I believe this should solve the issue for Foreman-on-Centos for plugin enablement, but I don't have such a test system available to me to validate if we need any additional protections for the tfm call.

@evgeni
Copy link
Contributor Author

evgeni commented Feb 9, 2021

The patch fixes it for Foreman too, yeah.

It does yield two warnings when executing the plugin:

[plugin:foreman] Failed to find prefix for SCL tfm, using /opt/rh
[plugin:foreman] Failed to find prefix for SCL tfm, using /opt/rh

But that's not bad as such -- we just don't have an SCL on EL8 and use system-ruby.

We could guard the tfm gem list command with a if type(self)._scls_matched:, then the warnings are gone too and nothing is missed (the ruby plugin collects the gem list for the system ruby already).

TurboTurtle added a commit to TurboTurtle/sos that referenced this issue Feb 9, 2021
It was found that if a system has `scl` available to it, and has a
non-scl package installed for a plugin that subclasses `SCLPlugin`, but
the scl packages are not installed, then the plugin will not be enabled
even for the non-scl collections.

This was due to a too-restrictive check if the plugin subclasses
`SCLPlugins` that prevented the normal plugin triggers from being
checked.

The future of Software Collections is uncertain to the sos project at
this time, but our current use of it is only 3 plugins; foreman,
postgresql, and redis.

As such, rather than splitting out `SCLPlugin` further into a distinct
separate subclass of a plugin and then having to deal with how to
determine which plugin class should be instantiated if both the scl and
non-scl plugin would otherwise be enabled, make the `SCLPlugin`
enablement conditions not prevent normal plugin enablement, and add
gates to the `_scl` methods provided by `SCLPlugin` to abort any
collection attempt if the specified scl is not detected.

If, at a later date, the project sees further (new) use of the
`SCLPlugin` then we can/will review this approach at that time.

Closes: sosreport#2407
Resolves: sosreport#2412

Signed-off-by: Jake Hunsaker <jhunsake@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants