Repository: RedHatInsights/insights-core

Issue:
`httpd_on_nfs` datasource is missed but there are rules depending on it
The `httpd_on_nfs` datasource is removed from the `default.py` module, but currently, there are rules depending on it.

We need to add it back.


Discussion:

Resolving patch:
diff --git a/insights/collect.py b/insights/collect.py
--- a/insights/collect.py
+++ b/insights/collect.py
@@ -165,6 +165,10 @@
         - name: insights.combiners.httpd_conf._HttpdConf
           enabled: true
 
+    # needed for httpd_on_nfs
+        - name: insights.parsers.mount.ProcMounts
+          enabled: true
+
     # needed for nginx_ssl_cert_enddate
         - name: insights.combiners.nginx_conf.NginxConfTree
           enabled: true
diff --git a/insights/specs/datasources/httpd.py b/insights/specs/datasources/httpd.py
--- a/insights/specs/datasources/httpd.py
+++ b/insights/specs/datasources/httpd.py
@@ -1,11 +1,14 @@
 """
 Custom datasources related to ``httpd``
 """
+import json
 from insights.core.context import HostContext
 from insights.core.dr import SkipComponent
 from insights.core.plugins import datasource
+from insights.parsers.mount import ProcMounts
 from insights.combiners.ps import Ps
 from insights.specs.datasources import get_running_commands
+from insights.core.spec_factory import DatasourceProvider
 
 
 @datasource(Ps, HostContext)
@@ -21,3 +24,33 @@ def httpd_cmds(broker):
     if cmds:
         return cmds
     raise SkipComponent
+
+
+@datasource(ProcMounts, HostContext)
+def httpd_on_nfs(broker):
+    """
+    Function to get the count of httpd opened file on nfs v4
+
+    Returns:
+        str: JSON string with keys: "httpd_ids", "nfs_mounts", "open_nfs_files"
+    """
+    mnt = broker[ProcMounts]
+    mps = mnt.search(mount_type='nfs4')
+    # get nfs 4.0 mount points
+    nfs_mounts = [m.mount_point for m in mps if 'vers' in m.mount_options and m.mount_options.vers.startswith("4")]
+    if nfs_mounts:
+        # get all httpd ps
+        httpd_pids = broker[HostContext].shell_out("pgrep httpd")
+        if httpd_pids:
+            open_nfs_files = 0
+            lsof_cmds = ["lsof -p {0}".format(pid) for pid in httpd_pids if pid]
+            # maybe there are thousands open files
+            for cmd in lsof_cmds:
+                for line in broker[HostContext].shell_out(cmd):
+                    items = line.split()
+                    if len(items) > 8 and items[8].startswith(tuple(nfs_mounts)):
+                        open_nfs_files += 1
+            result_dict = {"http_ids": httpd_pids, "nfs_mounts": nfs_mounts, "open_nfs_files": open_nfs_files}
+            relative_path = 'insights_commands/httpd_open_nfsV4_files'
+            return DatasourceProvider(content=json.dumps(result_dict), relative_path=relative_path)
+    raise SkipComponent
diff --git a/insights/specs/default.py b/insights/specs/default.py
--- a/insights/specs/default.py
+++ b/insights/specs/default.py
@@ -260,6 +260,7 @@ class DefaultSpecs(Specs):
     )
     httpd_cert_info_in_nss = foreach_execute(ssl_certificate.httpd_certificate_info_in_nss, '/usr/bin/certutil -d %s -L -n %s')
     httpd_error_log = simple_file("var/log/httpd/error_log")
+    httpd_on_nfs = httpd.httpd_on_nfs
     httpd24_httpd_error_log = simple_file("/opt/rh/httpd24/root/etc/httpd/logs/error_log")
     jbcs_httpd24_httpd_error_log = simple_file("/opt/rh/jbcs-httpd24/root/etc/httpd/logs/error_log")
     virt_uuid_facts = simple_file("/etc/rhsm/facts/virt_uuid.facts")


Test patch:
diff --git a/insights/tests/datasources/test_httpd.py b/insights/tests/datasources/test_httpd.py
--- a/insights/tests/datasources/test_httpd.py
+++ b/insights/tests/datasources/test_httpd.py
@@ -2,8 +2,39 @@
 from mock.mock import patch
 from insights.core.dr import SkipComponent
 from insights.core.context import HostContext
-from insights.specs.datasources.httpd import httpd_cmds
+from insights.specs.datasources.httpd import httpd_cmds, httpd_on_nfs
+from insights.parsers.mount import ProcMounts
 from insights.combiners.ps import Ps
+from insights.tests import context_wrap
+
+
+MOUNT_DATA = """
+/dev/mapper/root / ext4 rw,relatime,barrier=1,data=ordered 0 0
+/dev/mapper/httpd1 /httpd1 nfs4 rw,relatime,vers=4,barrier=1,data=ordered 0 0
+/dev/mapper/httpd2 /httpd2 nfs4 rw,relatime,vers=4,barrier=1,data=ordered 0 0
+""".strip()
+NFS_LSOF_666 = """
+zsh     3520 httpd    3r   REG  253,0   6940392    648646 /httpd1
+zsh     3520 httpd   11r   REG  253,0   9253600    648644 /httpd1
+zsh     3520 httpd   12u   CHR    5,0       0t0      1034 /dev/tty
+""".strip()
+NFS_LSOF_777 = """
+zsh     3520 httpd    3r   REG  253,0   6940392    648646 /httpd2
+zsh     3520 httpd   11r   REG  253,0   9253600    648644 /httpd2
+zsh     3520 httpd   12u   CHR    5,0       0t0      1034 /httpd2
+""".strip()
+
+
+class FakeContext(HostContext):
+    def shell_out(self, cmd, split=True, timeout=None, keep_rc=False, env=None, signum=None):
+        if 'pgrep' in cmd:
+            return '666', '777'
+        elif 'lsof -p 666' in cmd:
+            return NFS_LSOF_666.splitlines()
+        elif 'lsof -p 777' in cmd:
+            return NFS_LSOF_777.splitlines()
+
+        raise Exception
 
 
 # The ``get_running_commands()`` is tested in:
@@ -20,3 +51,12 @@ def test_httpd_cmds(run_cmds):
     run_cmds.return_value = []
     with pytest.raises(SkipComponent):
         httpd_cmds(broker)
+
+
+@patch('insights.specs.datasources.httpd.get_running_commands')
+def test_httpd_on_nfs(run_cmds):
+    broker = {ProcMounts: ProcMounts(context_wrap(MOUNT_DATA)), HostContext: FakeContext()}
+    result = httpd_on_nfs(broker)
+    assert '"http_ids": ["666", "777"]' in result.content[0]
+    assert '"open_nfs_files": 5' in result.content[0]
+    assert '"nfs_mounts": ["/httpd1", "/httpd2"]' in result.content[0]
diff --git a/insights/tests/datasources/test_package_provides.py b/insights/tests/datasources/test_package_provides.py
--- a/insights/tests/datasources/test_package_provides.py
+++ b/insights/tests/datasources/test_package_provides.py
@@ -72,7 +72,6 @@ def test_get_package():
     ctx = FakeContext()
 
     result = get_package(ctx, '/usr/bin/java')
-    print('result:', result)
     assert result == 'java-1.8.0-openjdk-headless-1.8.0.292.b10-1.el7_9.x86_64'
 
     result = get_package(ctx, '/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.292.b10-1.el7_9.x86_64/jre/bin/java')