Diagnostic Walkthrough¶
A simple use-case for troubleshooting is the identification of installed software on the system. In this example, we will examine checking a system for the usage of bash
based on data from the rpm
command. This “walkthrough” will avoid going into details. Instead, it will simply lay out how the use-case could be handled using insights-core
. More detailed tutorials can be found in the docs.
We’ll assume we have insights-core
already installed following the instructions on the README.rst. Next we need to import the necessary modules.
[1]:
import sys
sys.path.insert(0, "../..")
[2]:
from insights import rule, make_fail, make_pass, run
from insights.parsers.installed_rpms import InstalledRpms
The first import line has the most common components used when creating rules. The rule
decorator marks a function that encodes logic to be applied by the framework and the required or optional components it needs to execute. @rule
decorated functions use make_fail
or make_pass
to return results. The run
method executes the system, simplifying usage of insights-core
for small, standalone scripts and from the python interpreter.
We also import the InstalledRpms parser. This is a class that structures the results of the rpm -qa
command.
Next, we create our “rule” function.
[3]:
@rule(InstalledRpms)
def report(rpms):
rpm = rpms.get_max("bash")
if rpm:
return make_pass("BASH_INSTALLED", version=rpm.nvr)
return make_fail("BASH_INSTALLED")
Here, the report
method will let us know if the bash
package is installed, and if so, the latest version encountered. The name of the function isn’t important. The @rule
decorator defines the report
function as a “rule” component type and indicates that it depends on the InstalledRpms
parser. This parser will be passed into the function as the first argument.
The rest of the report
function is fairly easy to understand, noting that the get_max
function returns the maximum version encountered of the package specified, or None
if the package is not found.
Let’s try running this function using the run
method.
[4]:
results = run(report)
results[report]
[4]:
{'pass_key': 'BASH_INSTALLED',
'type': 'pass',
'version': u'bash-4.4.23-1.fc28'}
The run
command executed the framework collecting rpm
information from my system, parsing it using the InstalledRpms
class, and then running the report
function. It found that bash
was installed.
The results are keyed by function (report
in this case). Multiple functions can be executed, each with its own response.
The InstalledRpms class has structured the results of the rpm -qa
command, parsing the rows from the command output. That is, each package NVR is separated into its own fields. One consequence of this is that the package name is distinct. When we look for bash
, the parser doesn’t match, for example, bash-completion
(also on my system.) It also means the version information is understood. So, we can do things like check a range of versions.
First, let’s define our range using the bash
NVRs we care about. We’ll imagine there’s a particular bug that affects bash
starting in 4.4.16-1 and is fixed in 4.4.22-1.
[5]:
from insights.parsers.installed_rpms import InstalledRpm
lower = InstalledRpm.from_package("bash-4.4.16-1.fc27")
upper = InstalledRpm.from_package("bash-4.4.22-1.fc27")
Now, we’ll modify the report
function to check ranges.
[6]:
@rule(InstalledRpms)
def report(rpms):
rpm = rpms.get_max("bash")
if rpm and rpm >= lower and rpm < upper:
return make_fail("BASH_AFFECTED", version=rpm.nvr)
elif rpm:
return make_pass("BASH_AFFECTED", version=rpm.nvr)
else:
return make_pass("NO_BASH")
Now we can run this as before.
[7]:
results = run(report)
results[report]
[7]:
{'pass_key': 'BASH_AFFECTED', 'type': 'pass', 'version': u'bash-4.4.23-1.fc28'}
A few notes about this example:
- The code here could be packaged up in a script, along with other rules, to be easily reused.
- The rule can be executed against a live host, sosreport, Red Hat Insights archive, or a directory formed from an expanded archive.
- While we defined only a rule, we could also define other components like the command to be run and a parser to structure the content. The stand_alone.py is a simple example containing these three components.
The code above, (and this notebook) can be executed if insights-core
(and jupyter-notebook) is installed. So feel free to run and experiment with the example.