-
Notifications
You must be signed in to change notification settings - Fork 545
How to Write a Plugin
Plugins live in the sos.plugins package. This is the first place that a proper python package exists on the python path (e.g. ./sos/plugins)
Essentially you need to create a class that inherits from Plugin
and at least one of the provided tagging superclasses. Currently there is only one tagging superclass, RedHatPlugin
.
from sos.plugins import Plugin, RedHatPlugin
class MyPlugin(Plugin, RedHatPlugin):
pass
In order for a plugin to actually do any work one of the hook methods must be defined. The setup
hook is called during normal collection on every enabled plugin.
from sos.plugins import Plugin, RedHatPlugin
class CopyTest(Plugin, RedHatPlugin):
"""This plugin copies some stuff"""
def setup(self):
self.addCopySpecs([
"/path/to/something/interesting",
"/path/to/something/else/interesting",
])
The above will copy the two files specified in the addCopySpecs
method to the final archive.
If you wish to collect the output of a program as part of your collection process then you only need to call the collectExtOutput
method.
from sos.plugins import Plugin, RedHatPlugin
class CopyTest(Plugin, RedHatPlugin):
"""This plugin copies some stuff"""
def setup(self):
self.collectExtOutput("/path/to/bin -v")
self.collectExtOutput('/path/to/bin | /path/to/another/bin | grep -v "stuff I want to omit"')
The collectExtOutput
method will execute it's argument via the shell. The output of the command will be added to the report archive under sos_commands/plugin_name/mangled_command_name
. Additionally, the command will be added to the report index automatically.
You can inform sosreport that your plugin should not be run unless certain conditions are met. In order to do this define a checkenabled
method. Sosreport provides default behavior for this method if all you want to do is check for files on the system or for installed packages.
from sos.plugins import Plugin, RedHatPlugin
class DepTest(Plugin, RedHatPlugin):
"""This plugin depends on a file or package"""
files = ('/path/to/file/I/need',)
packages = ('nameOfPackageINeed',)
def setup(self):
self.addCopySpecs([
"/path/to/something",
"/path/to/something/else",
])
Note: if you use a tuple for files
or packages
be sure that you place the trailing comma in the case of a 1-tuple. ('some string')
does not create a 1-tuple, but ('some string',)
does.
Be aware that if any of the files or packages are found then the plugin will attempt to run. If you need to ensure that multiple files are in place or multiple packages are in place then you will want to implement your own checkenabled
method.
from sos.plugins import Plugin, RedHatPlugin
from os.path import exists
class DepTest(Plugin, RedHatPlugin):
"""This plugin depends on something"""
def checkenabled(self):
return exists('/path/to/thing/i/need') and exists('/path/to/other/thing/i/need')
def setup(self):
self.addCopySpecs([
"/path/to/something",
"/path/to/something/else",
])
Most plugins require super user access to perform their tasks. However, certain plugins may not have this requirement. If your plugin does not need root access then you can set a class-level variable requires_root
to False
.
from sos.plugins import Plugin, IndependentPlugin
class MyPlugin(Plugin, IndependentPlugin):
requires_root = False
def setup(self):
pass
If your plugin needs to run on multiple platforms you can do that a couple ways. If the rules for collection are the same on every platform (like for say JBOSS) then subclassing IndependentPlugin
is all you really need to do:
from sos.plugins import Plugin, IndependentPlugin
class MyPlugin(Plugin, IndependentPlugin):
def setup(self):
pass # do stuff
However, if you need to do different things on different platforms you need to define one plugin per platform, like so:
from sos.plugins import Plugin, RedHatPlugin, DebianPlugin
class MyRedHatPlugin(Plugin, RedHatPlugin):
name = "myplugin"
def setup(self):
pass # do red hat specific stuff
class MyDebianPlugin(Plugin, DebianPlugin):
name = "myplugin"
def setup(self):
pass # do debian specific stuff
Notice how both plugins have a class-level name
attribute. This should be the same for all platform-specific implementations of your plugin. The name attribute determines the name presented to the user for plugin selection as well as option definition.
In some cases you may wish to share certain bits between platform-specific plugins, in this case you can make a common shared superclass:
from sos.plugins import Plugin, RedHatPlugin, DebianPlugin
class MyPlugin(Plugin):
name = "myplugin"
def setup(self):
pass # do common things here
class MyRedHatPlugin(MyPlugin, RedHatPlugin):
def setup(self):
super(MyRedHatPlugin, self).setup()
pass # do red hat specific stuff
class MyDebianPlugin(MyPlugin, DebianPlugin):
def setup(self):
super(MyDebianPlugin, self).setup()
pass # do debian specific stuff
Note how the leaf classes are still the only ones that subclass things like RedHatPlugin
and DebianPlugin
. This ensures that your shared plugin class does not get run as a plugin on its own.