Embedded Content
insights-core
separates the return of results from their rendering.
This separation allows applications using insights-core
to produce
output appropriate to the application. So, for example, the Red Hat
Insights product utilizes several content artifacts (general
descriptions, specific descriptions, resolutions, etc.) while an
internal diagnostic system may have a single description. Each
application may also use different rendering or templating systems for
their UI layer. Finally, internationalization of responses may be
required.
Because of this separation, the methods that return results
(insights.core.plugins.make_pass
and
insights.core.plugins.make_fail
) should not provide
formatting themselves. Instead, keyword arguments (kwargs) are used to
pass information from the plugin to the caller for interpretation.
However, this separation adds unneeded complexity in the case of creating rules for individual, command line use. For this use-case, a conventional approach using a simple string or dictionary is available to embed content into the rule code.
CONTENT
Attribute
To embed content within a rule, create a CONTENT
attribute on the
rule module. This attribute can be a string or a dictionary.
CONTENT
as a String
When CONTENT
is a string, it is interpreted as a jinja2 template, and the kwargs of the
make_*
functions are interpolated into it. This would take place
for all responses in the module. If you want to scope content to a
particular rule, set the content
named argument in the @rule
declaration to the desired jinja2 string.
CONTENT
as a Dictionary
When CONTENT
is a dictionary, there are three possible ways to
specify template strings with results. A template can be associated with
an error_key (the first argument of the make_pass
or make_fail
functions,) or with the make_pass
and make_fail
commands
themselves, or both.
Dictionary keys which are references to make_pass
or make_fail
can be used to specify jinja2 template strings. These would apply to
any make_*
results in the module.
CONTENT = {
make_pass: "Good bash version: {{bash}}",
make_fail: "Bad bash version: {{bash}}"
}
Alternatively, one can use the error_key returned by the respective
make_*
functions to specify a jinja2 template string.
CONTENT = {
ERROR_KEY_GOOD_BASH: "Good bash version: {{bash}}",
ERROR_KEY_BAD_BASH: "Bad bash version: {{bash}}"
}
Finally, one can use the error_key to specify a make_*
set of jinja2
strings through an inner dictionary.
CONTENT = {
ERROR_KEY_BASH: {
make_pass: "Good bash version: {{bash}}",
make_fail: "Bad bash version: {{bash}}"
}
ERROR_KEY_TUNED: {
make_pass: "Good tuned version: {{tuned}}",
make_fail: "Bad tuned version: {{tuned}}"
}
}
This allows one to use a single error_key with a pass/fail pair.
The Examples section provides additional examples of each type of
CONTENT
usage.
make_metadata
Limitation
A limitation of the CONTENT
attribute occurs when adding embedded
content for the output of the make_metadata
function. Since this
method does not take an error_key, one must use the string version of
the CONTENT
attribute instead of the dictionary version.
In the case that you need multiple format strings in the module, you can
use the content
argument on the @rule
decorator to specify the
specific formatting for the rule.
Optional Dependencies
To use the CONTENT
formatting feature, you will need to install the
optional jinja2 module. In addition, when running insights on the
command line, you may want to install the colorama package for colorized
output. For example,
pip install colorama jinja2
Examples
A single string can be used for all results from a file. That is, the
CONTENT
attribute is applied without regard to the returned ERROR_KEY.
1 from insights import rule, make_pass, make_fail
2 from insights.parsers.installed_rpms import InstalledRpm, InstalledRpms
3
4 CONTENT = "Bash Bug Check: {{bash}}"
5
6 @rule(InstalledRpms)
7 def check_bash_bug(rpms):
8 bug_version = InstalledRpm.from_package('bash-4.4.14-1.any')
9 fix_version = InstalledRpm.from_package('bash-4.4.18-1.any')
10 current_version = rpms.get_max('bash')
11 if bug_version <= current_version < fix_version:
12 return make_fail('BASH_BUG', bash=current_version.nvr)
13 else:
14 return make_pass('BASH_BUG', bash=current_version.nvr)
The CONTENT
string will be used for both the make_fail
(line 12)
and make_pass
(line 14) classes, substituting the value of the
bash
kwarg (that is, current_version.nvr
.) In this case the
string acts as a label, and the fail or pass classification indicates if
the version an issue or not. Putting the above in a file,
bash_bug.py
and running on a system with a version outside the “bug”
range results in
1 % insights-run -p bash_bug
2 ---------
3 Progress:
4 ---------
5 P
6
7 ---------------
8 Rules Executed
9 ---------------
10 bash_bug.check_bash_bug - [PASS]
11 -----------------------------------------
12 Bash Bug Check: bash-4.4.23-1.fc28
13
14 ...
For a system with the bug, the output would be
1 % insights-run -p bash_bug
2 ---------
3 Progress:
4 ---------
5 R
6
7 ---------------
8 Rules Executed
9 ---------------
10 bash_bug.check_bash_bug - [FAIL]
11 -----------------------------------------
12 Bash Bug Check: bash-4.4.15-1.fc28
13
14 ...
To make the distinction more explicit, or to return different output in the case
of a pass or a fail, we use a dictionary for the CONTENT
attribute.
1 from insights import rule, make_pass, make_fail
2 from insights.parsers.installed_rpms import InstalledRpm, InstalledRpms
3
4 CONTENT = {
5 make_fail: "Bash bug found! Version: {{bash}}",
6 make_pass: "Bash bug not found: {{bash}}."
7 }
8
9 @rule(InstalledRpms)
10 def check_bash_bug(rpms):
11 bug_version = InstalledRpm.from_package('bash-4.4.14-1.any')
12 fix_version = InstalledRpm.from_package('bash-4.4.18-1.any')
13 current_version = rpms.get_max('bash')
14 if bug_version <= current_version < fix_version:
15 return make_fail('BASH_BUG', bash=current_version.nvr)
16 else:
17 return make_pass('BASH_BUG', bash=current_version.nvr)
With this version, the “pass” use case would generate output such as
1 % insights-run -p bash_bug
2 ---------
3 Progress:
4 ---------
5 P
6
7 ---------------
8 Rules Executed
9 ---------------
10 bash_bug.check_bash_bug - [PASS]
11 -----------------------------------------
12 Bash bug not found: bash-4.4.23-1.fc28.
13
14 ...
and the fail case would output
1 % insights-run -p bash_bug
2 ---------
3 Progress:
4 ---------
5 R
6
7 ---------------
8 Rules Executed
9 ---------------
10 bash_bug.check_bash_bug - [FAIL]
11 -----------------------------------------
12 Bash bug found! Version: bash-4.4.15-1.fc28.
13
14 ...
If you had multiple error keys and needed to distinguish between the content for
them, instead of using the response classes as the CONTENT
keys, you would
use the error key values. If you needed to distinguish between the pass and
failure states of a single key, use a dictionary with the response class as the
keys.
1 from insights import rule, make_pass, make_fail
2 from insights.parsers.installed_rpms import InstalledRpm, InstalledRpms
3
4 CONTENT = {
5 # for any response with error key of 'SUPER_BASH_BUG'
6 'SUPER_BASH_BUG': "Super Bash bug found! Version: {{bash}}",
7
8 # distinguish between the response types of the 'BASH_BUG' error key.
9 'BASH_BUG': {
10 make_fail:"Bash bug found! Version: {{bash}}",
11 make_pass: "Bash bug not found! Version: {{bash}}"
12 }
13 }
14
15 @rule(InstalledRpms)
16 def check_bash_bug(rpms):
17 super_bug_version = InstalledRpm.from_package('bash-4.4.12-1.any')
18 bug_version = InstalledRpm.from_package('bash-4.4.14-1.any')
19 fix_version = InstalledRpm.from_package('bash-4.4.18-1.any')
20 current_version = rpms.get_max('bash')
21 if super_bug_version == current_version:
22 return make_fail('SUPER_BASH_BUG', bash=current_version.nvr)
23
24 if bug_version <= current_version < fix_version:
25 return make_fail('BASH_BUG', bash=current_version.nvr)
26 else:
27 return make_pass('BASH_BUG', bash=current_version.nvr)