Rule Using Existing Parser and Combiner

Determine rule logic

The most effective way to get started in developing a rule is first to identify the problem you want to address.

For the purposes of this tutorial we’ll look at a very simple scenario. Sometimes when researching an issue one of the things that we might need to know is which Red Hat OS the host is running. For simplicity sake, in this example we will concentrate only on determining if the red hat release is Fedora.

For this case there is one thing we need to check:

  1. Is the Red Hat release Fedora:

Identify Parsers

  • We can check Red Hat Release using the RedhatRelease parser.

Develop Plugin

Now that we have identified the required parsers, let’s get started on developing our plugin.

Create a file called is_fedora.py in a Python package called tutorial.

(env)[userone@hostone ~]$ cd ~/work/insights-core-tutorials/mycomponents/rules
(env)[userone@hostone rules]$ touch is_fedora.py

Open is_fedora.py in your text editor of choice and start by stubbing out the rule function and imports.

1 from insights.parsers.redhat_release import RedhatRelease
2 from insights import rule, make_fail, make_pass
3
4 @rule(RedhatRelease)
5 def report(rhrel):
6     pass

Let’s go over each line and describe the details:

1 from insights.parsers.redhat_release import RedhatRelease

Parsers you want to use must be imported. You must pass the parser class objects directly to the @rule decorator to declare them as dependencies for your rule.

2 from insights import rule, make_fail, make_pass

rule is a function decorator used to specify your main plugin function. Combiners have a set of optional dependencies that are specified via the requires kwarg.

make_fail, make_pass are formatting functions used to format the return value of a rule function.

 6 ERROR_KEY_IS_FEDORA = "IS_FEDORA"
 7
 8 CONTENT = {
 9     ERROR_KEY_IS_FEDORA: "This machine ({{hostname}}) runs {{product}}.",
10 }

Here we define the Jinja2 template for message to be displayed for either response tag

12 @rule(RedhatRelease)

Here we are specifying that this rule requires the output of the insights.parsers.redhat_release.RedhatRelease,

Now let’s add the rule logic

12 @rule(RedhatRelease, content=CONTENT)
13 def report(rhrel):
14     """Fires if the machine is running Fedora."""
15
16     if "Fedora" in rel.product:
17         return make_pass(ERROR_KEY_IS_FEDORA, hostname=hostname.hostname, product=rel.product)
18     else:
19         return make_fail(ERROR_KEY_IS_FEDORA, hostname=hostname.hostname, product=rel.product)

Now lets look at what the rule is doing.

The RedhatRelease parser parses content from the /etc/redhat-release file on the host it is running on and returns an object containing the Red Hat OS information for the host.

16     if "Fedora" in rhrel.product:
17         return make_pass(ERROR_KEY_IS_FEDORA, hostname=hostname.hostname, product=rel.product)
18     else:
19         return make_fail(ERROR_KEY_IS_FEDORA, hostname=hostname.hostname, product=rel.product)

Here we check to see if the value Fedora is in the “product” property of the “rhrel” object. If true then the rule returns a response telling us that the host is indeed running Fedora, along with the product information returned by the parser. If false then the rule returns a response telling us that the host is not running Fedora, along with the product information returned by the parser.

Develop Tests

Start out by creating a test_is_fedora.py module in a tests package.

(env)[userone@hostone ~]$ cd ~/work/insights-core-tutorials/tests/rules
(env)[userone@hostone rules]$ touch __init__.py
(env)[userone@hostone rules]$ touch test_is_fedora.py

Open test_is_fedora.py in your text editor of choice and start by stubbing out a test and the required imports.

1 from .. import is_fedora
2 from insights.specs import Specs
3 from insights.tests import InputData, archive_provider
4 from insights.core.plugins import make_fail, make_pass
5
6
7 @archive_provider(is_fedora.report)
8 def integration_test():
9     pass

The framework provides an integration test framework that allows you to define an InputData object filled with raw examples of files required by your rule and an expected response. The object is evaluated by the pipeline as it would be in a production context, after which the response is compared to your expected output.

The @archive_provider decorator registers your test function with the framework. This function must be a generator that yields InputData and an expected response in a two tuple. The @archive_provider decorator takes one parameter, the rule function to test.

The bulk of the work in building a test for a rule is in defining the InputData object. If you remember our rule we accept RedhatRelease. We will define a data snippet for each test.

FEDORA = "Fedora release 28 (Twenty Eight)".strip()
RHEL = "Red Hat Enterprise Linux Server release 7.4 (Maipo)".strip()
TEST_HOSTNAME = "testhost.someplace.com"

Next for each test we need to build InputData objects and populate it with the content and build the expected return. Then finally we need to yield the pair.

16 input_data = InputData("test_fedora")
17 input_data.add(Specs.redhat_release, FEDORA)
18 input_data.add(Specs.hostname, TEST_HOSTNAME)
19 expected = make_pass("IS_FEDORA", hostname=TEST_HOSTNAME, product="Fedora")
20
21 yield input_data, expected
22
23 input_data = InputData("test_rhel")
24 input_data.add(Specs.redhat_release, RHEL)
25 input_data.add(Specs.hostname, TEST_HOSTNAME)
26 expected = make_fail("IS_FEDORA", hostname=TEST_HOSTNAME, product="Red Hat Enterprise Linux Server")
27
28 yield input_data, expected

Now for the entire test:

 1from .. import is_fedora
 2from insights.specs import Specs
 3from insights.tests import InputData, archive_provider
 4from insights.core.plugins import make_fail, make_pass
 5
 6FEDORA = "Fedora release 28 (Twenty Eight)"
 7RHEL = "Red Hat Enterprise Linux Server release 7.4 (Maipo)"
 8TEST_HOSTNAME = "testhost.someplace.com"
 9
10
11@archive_provider(is_fedora.report)
12def integration_test():
13
14    input_data = InputData("test_fedora")
15    input_data.add(Specs.redhat_release, FEDORA)
16    input_data.add(Specs.hostname, TEST_HOSTNAME)
17    expected = make_pass("IS_FEDORA", hostname=TEST_HOSTNAME, product="Fedora")
18
19
20    yield input_data, expected
21
22    input_data = InputData("test_rhel")
23    input_data.add(Specs.redhat_release, RHEL)
24    input_data.add(Specs.hostname, TEST_HOSTNAME)
25    expected = make_fail("IS_FEDORA", hostname=TEST_HOSTNAME, product="Red Hat Enterprise Linux Server")
26
27    yield input_data, expected