Skip to content

Commit 59b372c

Browse files
committed
Introduce a new option to mark plugins optional
ServiceReport by default runs all the plugins available inside the validate package. The validate package does have some workload specific plugin which may not required to run all the time. For example HTX plugin has limited use case (in testing OpenPOWER systems) and we may not required to test HTX configuration on every machine by default. This patch adds an infrastructure to mark plugins optional which are specific to a particular workload and may not required to run by default. If a plugin is marked optional then it will not get executed by default. The format of listing the applicable plugins using -l (--list) option has changed. A new column (Tag) has been introduced that shows a plugin is optional or mandatory. Listing applicable plugins: $ ./servicereport -l servicereport 2.2.1 The following plugins are applicable: Name Tags Description daemon M Daemon availability checks fadump M FADump configuration check htx M HTX configuration check package M Package availability check Tag Info: M: Mandatory plugin (runs by default) O: Optional plugin (use -o option to enable) Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com>
1 parent c9feebe commit 59b372c

3 files changed

Lines changed: 100 additions & 32 deletions

File tree

servicereportpkg/__init__.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ def parse_commandline_args(args):
4848
nargs='+', default=None,
4949
help="validates the specified plugins only")
5050

51+
parser.add_argument("-o", "--optional", dest="optional",
52+
nargs='+', default=None,
53+
help="run the specified optional plugins")
54+
5155
parser.add_argument("-q", "--quiet", action="store_true",
5256
dest="quite", default=False,
5357
help="no output on console")
@@ -64,6 +68,11 @@ def parse_commandline_args(args):
6468
dest="verbose", default=0,
6569
help="increase the logging verbosity")
6670

71+
parsed_argument = parser.parse_args(args)
72+
73+
if parsed_argument.plugins and parsed_argument.optional:
74+
parser.error("-o(--optional) is not allowed with -p(--pluigns)\n"
75+
"\t\t\tList all the plugins against -p option only.")
6776
return parser.parse_args(args)
6877

6978

servicereportpkg/validate/__init__.py

Lines changed: 85 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -27,45 +27,99 @@ def __init__(self, cmd_opts):
2727
self.plugin_handler = PluginHandler(self.scheme_handler)
2828
self.validation_results = OrderedDict()
2929

30-
def get_plugin_dir(self, plugins=None):
31-
"""Returns an ordered directory of list of executable plugins"""
30+
def get_applicable_plugins(self):
31+
"""Returns a dictionary of applicable plugins"""
3232

33-
plugin_dir_tmp = OrderedDict()
33+
plugins = {}
3434

3535
for plugin in self.plugin_handler.get_applicable_plugins():
3636
plugins_obj = plugin()
3737
plugin_name = plugins_obj.get_name().lower()
38-
if plugin_name not in plugin_dir_tmp.keys():
39-
plugin_dir_tmp[plugin_name] = []
40-
plugin_dir_tmp[plugin_name].append(plugins_obj)
41-
42-
# By default plugins are executed in sorted order but If plugins
43-
# are specified using -p option then the execution order should be
44-
# same as specified on command line
45-
if plugins:
46-
plugin_dir = OrderedDict()
47-
for plugin in plugins:
48-
plugin = plugin.lower()
49-
if plugin in plugin_dir_tmp.keys():
50-
if plugin not in plugin_dir.keys():
51-
plugin_dir[plugin] = plugin_dir_tmp[plugin]
52-
else:
53-
print("%s plugin is not applicable" % plugin)
54-
55-
return plugin_dir
56-
57-
return OrderedDict(sorted(plugin_dir_tmp.items(),
58-
key=lambda tmp: tmp[0]))
38+
39+
if plugin_name not in plugins:
40+
plugins[plugin_name] = []
41+
42+
plugins[plugin_name].append(plugins_obj)
43+
44+
return plugins
45+
46+
def is_plugin_executable(self, plugin_name, plugin_obj):
47+
"""Check whether the give plugin is executable in current system
48+
environment"""
49+
50+
if self.cmd_opts.plugins:
51+
return plugin_name in self.cmd_opts.plugins
52+
53+
if plugin_obj.is_optional():
54+
if self.cmd_opts.optional:
55+
return plugin_name in self.cmd_opts.optional
56+
57+
return False
58+
59+
return True
60+
61+
def arrange_execution_order(self, exe_plugins):
62+
"""Decides the plugin execution order"""
63+
64+
# Obey the order in which plugin are listed against -p or
65+
# --plugins option
66+
if self.cmd_opts.plugins:
67+
od_exe_plugin = OrderedDict()
68+
for plugin in self.cmd_opts.plugins:
69+
if plugin in exe_plugins:
70+
od_exe_plugin[plugin] = exe_plugins[plugin]
71+
72+
return od_exe_plugin
73+
74+
return OrderedDict(sorted(exe_plugins.items()))
75+
76+
def verify_listed_plugins(self, applicable_plugins, plugins):
77+
"""Find and print if any invalid plugin is listed by user"""
78+
79+
for plugin in plugins:
80+
if plugin not in applicable_plugins:
81+
print("Warning: %s plugin is either invalid or not applicable "
82+
"to this system.\n" % plugin)
83+
84+
def get_executable_plugins(self):
85+
"""Return a dictionary of executable plugins"""
86+
87+
exe_plugins = {}
88+
89+
applicable_plugins = self.get_applicable_plugins()
90+
91+
if self.cmd_opts.plugins:
92+
self.verify_listed_plugins(applicable_plugins,
93+
self.cmd_opts.plugins)
94+
95+
if self.cmd_opts.optional:
96+
self.verify_listed_plugins(applicable_plugins,
97+
self.cmd_opts.optional)
98+
99+
for plugin in applicable_plugins:
100+
plugin_objs = applicable_plugins[plugin]
101+
if self.is_plugin_executable(plugin, plugin_objs[0]):
102+
exe_plugins[plugin] = plugin_objs
103+
104+
return self.arrange_execution_order(exe_plugins)
59105

60106
def list_applicable_plugins(self):
61107
"""List all the applicable plugins"""
62108

63-
plugins = self.get_plugin_dir()
109+
plugins = self.get_applicable_plugins()
64110
print("The following plugins are applicable:\n")
111+
print(" {0:20}{1:20}{2}\n".format("Name", "Tags", "Description"))
65112
for plugin in plugins:
66-
print(" {0:25}{1}".format(plugin,
67-
plugins[plugin][0].get_description()))
113+
if not plugins[plugin][0].is_optional():
114+
print(" {0:20}{1:20}{2}".format(plugin, "M",
115+
plugins[plugin][0].get_description()))
116+
else:
117+
print(" {0:20}{1:20}{2}".format(plugin, "O",
118+
plugins[plugin][0].get_description()))
68119

120+
print("\n{0}\n{1}\n{2}".format("Tag Info: ",
121+
"M: Mandatory plugin (runs by default)",
122+
"O: Optional plugin (use -o option to enable)"))
69123

70124
def do_execute_plugin(self, plugin):
71125
"""Execute the plugin"""
@@ -82,7 +136,7 @@ def execute_plugins(self):
82136
handler identifier and execute the plugin"""
83137

84138
successful_plugin_obj = []
85-
plugin_dir = self.get_plugin_dir(self.cmd_opts.plugins)
139+
plugin_dir = self.get_executable_plugins()
86140

87141
for plugin in plugin_dir:
88142
change_log_identifier(TOOL_NAME + '.' + plugin, self.log)
@@ -95,7 +149,6 @@ def execute_plugins(self):
95149
self.do_execute_plugin(plugin_obj)
96150
successful_plugin_obj.append(plugin_obj)
97151

98-
99152
change_log_identifier(TOOL_NAME, self.log)
100153
for plugin_obj in successful_plugin_obj:
101154
if plugin_obj.get_name() not in self.validation_results.keys():
@@ -108,11 +161,11 @@ def validate(self):
108161

109162
# Make sure that if -d (--dump) is provided then only
110163
# dump plugin should run
111-
if self.cmd_opts.dump and self.cmd_opts.plugins is None:
164+
if self.cmd_opts.dump:
112165
if is_string_in_file("fadump=on", "/proc/cmdline"):
113-
self.cmd_opts.plugins = ["FADump"]
166+
self.cmd_opts.plugins = ["fadump"]
114167
else:
115-
self.cmd_opts.plugins = ["Kdump"]
168+
self.cmd_opts.plugins = ["kdump"]
116169

117170
self.execute_plugins()
118171
return self.validation_results

servicereportpkg/validate/plugins/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class Plugin(object):
1616
def __init__(self):
1717
self.name = Plugin.__name__
1818
self.description = Plugin.__doc__
19+
self.optional = False
1920
self.log = get_default_logger()
2021
self.checks = []
2122

@@ -31,6 +32,11 @@ def get_description(self):
3132

3233
return self.description
3334

35+
def is_optional(self):
36+
"""Return True if plugin is optional else False"""
37+
38+
return self.optional
39+
3440
def get_plugin_status(self):
3541
"""Returns the overall status of the plugin. Returns True only if all
3642
the checks succeed else False"""

0 commit comments

Comments
 (0)