Blob Blame History Raw
From c20bd8d489c45401db55cf89bf7d4d0f7623a4fe Mon Sep 17 00:00:00 2001
From: Jan Jansky <jjansky@redhat.com>
Date: Thu, 6 Feb 2020 08:56:11 +0100
Subject: [PATCH] [networking] options to limit namespaces

* Added posibility to define namespaces with
parameter namespaces = "". Posible regexp
like "eth* ens4".
* Added inspect_namespaces which defines how
many namespaces should be inspected, by
default unlimited
* Added ethtool_namespaces variable which
is by default true and if set to false it
will not execute ethtool commands for
namespaces
* Changed options for OpenStack environment
where ethtool_namespaces=False and
inspect_namespaces = 200

Closes: #1916

Signed-off-by: Jan Jansky <jjansky@redhat.com>
Signed-off-by: Pavel Moravec <pmoravec@redhat.com>
---
--- a/sos/plugins/networking.py
+++ b/sos/plugins/networking.py
@@ -8,7 +8,7 @@

 from sos.plugins import Plugin, RedHatPlugin, UbuntuPlugin, DebianPlugin
 from os import listdir
-import re
+from re import match
 
 
 class Networking(Plugin):
@@ -17,10 +17,17 @@
     plugin_name = "networking"
     profiles = ('network', 'hardware', 'system')
     trace_host = "www.example.com"
-    option_list = [(
+    option_list = [
         ("traceroute", "collect a traceroute to %s" % trace_host, "slow",
-         False)
-    )]
+         False),
+        ("namespace_pattern", "Specific namespaces pattern to be " +
+         "collected, namespaces pattern should be separated by whitespace " +
+         "as for example \"eth* ens2\"", "fast", ""),
+        ("namespaces", "Number of namespaces to collect, 0 for unlimited. " +
+         "Incompatible with the namespace_pattern plugin option", "slow", 0),
+        ("ethtool_namespaces", "Define if ethtool commands should be " +
+         "collected for namespaces", "slow", True)
+    ]
 
     # switch to enable netstat "wide" (non-truncated) output mode
     ns_wide = "-W"
@@ -196,8 +203,41 @@
         # per-namespace.
         ip_netns_file = self.get_cmd_output_now("ip netns")
         cmd_prefix = "ip netns exec "
+        # Regex initialization outside of for loop
         if ip_netns_file:
-            for namespace in self.get_ip_netns(ip_netns_file):
+            if self.get_option("namespace_pattern"):
+                pattern = '(?:%s$)' % '$|'.join(
+                        self.get_option("namespace_pattern").split()
+                        ).replace('*', '.*')
+            out_ns = []
+            with open(ip_netns_file, 'r') as file:
+                ip_netns = file.read()
+            for line in ip_netns.splitlines():
+                # If there's no namespaces, no need to continue
+                if line.startswith("Object \"netns\" is unknown") \
+                        or line.isspace() \
+                        or line[:1].isspace():
+                    continue
+
+                # if namespace_pattern defined, append only namespaces
+                # matching with pattern
+                if self.get_option("namespace_pattern"):
+                    if bool(match(pattern, line)):
+                        out_ns.append(line.partition(' ')[0])
+
+                # if namespaces is defined and namespace_pattern is not defined
+                # remove from out_ns namespaces with higher index than defined
+                elif self.get_option("namespaces") != 0:
+                    out_ns.append(line.partition(' ')[0])
+                    if len(out_ns) == self.get_option("namespaces"):
+                        self._log_warn("Limiting namespace iteration " +
+                                   "to first %s namespaces found"
+                                   % self.get_option("namespaces"))
+                        break
+                else:
+                    out_ns.append(line.partition(' ')[0])
+
+            for namespace in out_ns:
                 ns_cmd_prefix = cmd_prefix + namespace + " "
                 self.add_cmd_output([
                     ns_cmd_prefix + "ip address show",
@@ -208,25 +248,27 @@
                     ns_cmd_prefix + "netstat -s",
                     ns_cmd_prefix + "netstat %s -agn" % self.ns_wide
                 ])
-
-            # Devices that exist in a namespace use less ethtool
-            # parameters. Run this per namespace.
-            for namespace in self.get_ip_netns(ip_netns_file):
-                ns_cmd_prefix = cmd_prefix + namespace + " "
-                netns_netdev_list = self.call_ext_prog(ns_cmd_prefix +
+            # Collect ethtool commands only when ethtool_namespaces
+            # is set to true.
+            if self.get_option("ethtool_namespaces"):
+                # Devices that exist in a namespace use less ethtool
+                # parameters. Run this per namespace.
+                for namespace in out_ns:
+                    ns_cmd_prefix = cmd_prefix + namespace + " "
+                    netns_netdev_list = self.call_ext_prog(ns_cmd_prefix +
                                                        "ls -1 /sys/class/net/")
-                for eth in netns_netdev_list['output'].splitlines():
-                    # skip 'bonding_masters' file created when loading the
-                    # bonding module but the file does not correspond to
-                    # a device
-                    if eth == "bonding_masters":
-                        continue
-                    self.add_cmd_output([
-                        ns_cmd_prefix + "ethtool " + eth,
-                        ns_cmd_prefix + "ethtool -i " + eth,
-                        ns_cmd_prefix + "ethtool -k " + eth,
-                        ns_cmd_prefix + "ethtool -S " + eth
-                    ])
+                    for eth in netns_netdev_list['output'].splitlines():
+                        # skip 'bonding_masters' file created when loading the
+                        # bonding module but the file does not correspond to
+                        # a device
+                        if eth == "bonding_masters":
+                            continue
+                        self.add_cmd_output([
+                            ns_cmd_prefix + "ethtool " + eth,
+                            ns_cmd_prefix + "ethtool -i " + eth,
+                            ns_cmd_prefix + "ethtool -k " + eth,
+                            ns_cmd_prefix + "ethtool -S " + eth
+                        ])
 
         return

--- a/sos/policies/redhat.py
+++ b/sos/policies/redhat.py
@@ -192,8 +192,6 @@
 _opts_verify = SoSOptions(verify=True)
 _opts_all_logs = SoSOptions(all_logs=True)
 _opts_all_logs_verify = SoSOptions(all_logs=True, verify=True)
-_opts_all_logs_no_lsof = SoSOptions(all_logs=True,
-                                    plugopts=['process.lsof=off'])
 _cb_plugs = ['abrt', 'block', 'boot', 'dnf', 'dracut', 'filesys', 'grub2',
              'hardware', 'host', 'kernel', 'logs', 'lvm2', 'memory', 'rpm',
              'process', 'systemd', 'yum', 'xfs']
@@ -208,6 +206,10 @@
 
 RHOSP = "rhosp"
 RHOSP_DESC = "Red Hat OpenStack Platform"
+RHOSP_OPTS = SoSOptions(plugopts=[
+                             'process.lsof=off',
+                             'networking.ethtool_namespaces=False',
+                             'networking.namespaces=200'])
 
 RHOCP = "ocp"
 RHOCP_DESC = "OpenShift Container Platform by Red Hat"
@@ -221,7 +223,6 @@
 CB_OPTS = SoSOptions(verify=True, all_logs=True, onlyplugins=_cb_plugs)
 CB_NOTE = ("Data collection will be limited to a boot-affecting scope")
 
-NOTE_SIZE = "This preset may increase report size"
 NOTE_TIME = "This preset may increase report run time"
 NOTE_SIZE_TIME = "This preset may increase report size and run time"
 
@@ -229,8 +230,7 @@
     RHV: PresetDefaults(name=RHV, desc=RHV_DESC, note=NOTE_TIME,
                         opts=_opts_verify),
     RHEL: PresetDefaults(name=RHEL, desc=RHEL_DESC),
-    RHOSP: PresetDefaults(name=RHOSP, desc=RHOSP_DESC, note=NOTE_SIZE,
-                          opts=_opts_all_logs_no_lsof),
+    RHOSP: PresetDefaults(name=RHOSP, desc=RHOSP_DESC, opts=RHOSP_OPTS),
     RHOCP: PresetDefaults(name=RHOCP, desc=RHOCP_DESC, note=NOTE_SIZE_TIME,
                           opts=_opts_all_logs_verify),
     RH_SATELLITE: PresetDefaults(name=RH_SATELLITE, desc=RH_SATELLITE_DESC,