diff --git a/docs/custom_datasources_index.rst b/docs/custom_datasources_index.rst index 6e807cecbf..14d39e44fa 100644 --- a/docs/custom_datasources_index.rst +++ b/docs/custom_datasources_index.rst @@ -71,7 +71,7 @@ insights.specs.datasources.httpd -------------------------------- .. automodule:: insights.specs.datasources.httpd - :members: httpd_cmds + :members: httpd_cmds, httpd_on_nfs :show-inheritance: :undoc-members: diff --git a/insights/collect.py b/insights/collect.py index 61cdf4e25d..bd9df23166 100755 --- 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 index 45515a8394..fb9ff25d1b 100644 --- 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 index bd92f780a4..f6fc0714f1 100644 --- 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") diff --git a/insights/tests/datasources/test_httpd.py b/insights/tests/datasources/test_httpd.py index b87f3dda95..32f1008ee9 100644 --- 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 index 5bb06d8fa8..dad810e330 100644 --- 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')