예제 #1
0
    def setup(self):
        self.add_copy_spec([
            "/etc/firewalld/firewalld.conf",
            "/etc/firewalld/*.xml",
            "/etc/firewalld/icmptypes/*.xml",
            "/etc/firewalld/services/*.xml",
            "/etc/firewalld/zones/*.xml",
            "/etc/sysconfig/firewalld",
            "/var/log/firewalld",
        ])

        # collect nftables ruleset
        nft_pred = SoSPredicate(self,
                                kmods=['nf_tables', 'nfnetlink'],
                                required={'kmods': 'all'})
        self.add_cmd_output("nft list ruleset", pred=nft_pred, changes=True)

        # use a 10s timeout to workaround dbus problems in
        # docker containers.
        self.add_cmd_output([
            "firewall-cmd --list-all-zones",
            "firewall-cmd --direct --get-all-chains",
            "firewall-cmd --direct --get-all-rules",
            "firewall-cmd --direct --get-all-passthroughs",
            "firewall-cmd --permanent --list-all-zones",
            "firewall-cmd --permanent --direct --get-all-chains",
            "firewall-cmd --permanent --direct --get-all-rules",
            "firewall-cmd --permanent --direct --get-all-passthroughs",
            "firewall-cmd --state", "firewall-cmd --get-log-denied"
        ],
                            timeout=10)
예제 #2
0
 def setup(self):
     self.add_cmd_output([
         "ipvsadm -Ln", "ipvsadm -Ln --connection",
         "ipvsadm -Ln --persistent-conn", "ipvsadm -Ln --rate",
         "ipvsadm -Ln --stats", "ipvsadm -Ln --thresholds",
         "ipvsadm -Ln --timeout"
     ],
                         pred=SoSPredicate(self, kmods=['ip_vs']))
예제 #3
0
    def setup(self):
        self.add_copy_spec(
            ["/etc/docker/daemon.json", "/var/lib/docker/repositories-*"])

        self.add_journal(units="docker")
        self.add_cmd_output("ls -alhR /etc/docker")

        self.set_cmd_predicate(SoSPredicate(self, services=["docker"]))

        subcmds = [
            'events --since 24h --until 1s', 'info', 'images', 'network ls',
            'ps', 'ps -a', 'stats --no-stream', 'version', 'volume ls'
        ]

        for subcmd in subcmds:
            self.add_cmd_output("docker %s" % subcmd)

        # separately grab these separately as they can take a *very* long time
        if self.get_option('size'):
            self.add_cmd_output('docker ps -as')
            self.add_cmd_output('docker system df')

        nets = self.get_command_output('docker network ls')

        if nets['status'] == 0:
            n = [n.split()[1] for n in nets['output'].splitlines()[1:]]
            for net in n:
                self.add_cmd_output("docker network inspect %s" % net)

        ps_cmd = 'docker ps -q'
        if self.get_option('all'):
            ps_cmd = "%s -a" % ps_cmd

        fmt = '{{lower .Repository}}:{{lower .Tag}} {{lower .ID}}'
        img_cmd = "docker images --format='%s'" % fmt
        vol_cmd = 'docker volume ls -q'

        containers = self._get_docker_list(ps_cmd)
        images = self._get_docker_list(img_cmd)
        volumes = self._get_docker_list(vol_cmd)

        for container in containers:
            self.add_cmd_output("docker inspect %s" % container,
                                subdir='containers')
            if self.get_option('logs'):
                self.add_cmd_output("docker logs -t %s" % container,
                                    subdir='containers')

        for img in images:
            name, img_id = img.strip().split()
            insp = name if 'none' not in name else img_id
            self.add_cmd_output("docker inspect %s" % insp, subdir='images')

        for vol in volumes:
            self.add_cmd_output("docker volume inspect %s" % vol,
                                subdir='volumes')
예제 #4
0
    def collect_iptable(self, tablename):
        """ When running the iptables command, it unfortunately auto-loads
        the modules before trying to get output.  Some people explicitly
        don't want this, so check if the modules are loaded before running
        the command.  If they aren't loaded, there can't possibly be any
        relevant rules in that table """

        modname = "iptable_" + tablename
        cmd = "iptables -t " + tablename + " -nvL"
        self.add_cmd_output(cmd, pred=SoSPredicate(self, kmods=[modname]))
예제 #5
0
파일: crio.py 프로젝트: xhe123/sos
    def setup(self):
        self.add_copy_spec([
            "/etc/containers", "/etc/crictl.yaml", "/etc/crio/crio.conf",
            "/etc/crio/seccomp.json", "/etc/systemd/system/cri-o.service",
            "/etc/sysconfig/crio-*"
        ])

        self.add_env_var(
            ['HTTP_PROXY', 'HTTPS_PROXY', 'NO_PROXY', 'ALL_PROXY'])

        self.add_journal(units="crio")
        self.add_cmd_output("ls -alhR /etc/cni")

        # base cri-o installation does not require cri-tools, which is what
        # supplies the crictl utility
        self.set_cmd_predicate(SoSPredicate(self, packages=['cri-tools']))

        subcmds = [
            'info',
            'images',
            'pods',
            'ps',
            'ps -a',
            'ps -v',
            'stats',
            'version',
        ]

        self.add_cmd_output(["crictl %s" % s for s in subcmds])

        ps_cmd = 'crictl ps --quiet'
        if self.get_option('all'):
            ps_cmd = "%s -a" % ps_cmd

        img_cmd = 'crictl images --quiet'
        pod_cmd = 'crictl pods --quiet'

        containers = self._get_crio_list(ps_cmd)
        images = self._get_crio_list(img_cmd)
        pods = self._get_crio_list(pod_cmd)

        for container in containers:
            self.add_cmd_output("crictl inspect %s" % container)
            if self.get_option('logs'):
                self.add_cmd_output("crictl logs -t %s" % container,
                                    subdir="containers")

        for image in images:
            self.add_cmd_output("crictl inspecti %s" % image, subdir="images")

        for pod in pods:
            self.add_cmd_output("crictl inspectp %s" % pod, subdir="pods")
예제 #6
0
파일: sssd.py 프로젝트: xhe123/sos
    def setup(self):
        self.add_copy_spec([
            "/etc/sssd/sssd.conf",
            "/var/log/sssd/*",
            "/var/lib/sss/pubconf/krb5.include.d/*",
            # SSSD 1.14
            "/etc/sssd/conf.d/*.conf"
        ])

        # call sssctl commands only when sssd service is running,
        # otherwise the command timeouts
        sssd_pred = SoSPredicate(self, services=["sssd"])
        self.add_cmd_output("sssctl config-check", pred=sssd_pred)

        # if predicate fails, domain["status"] = None and thus we skip parsing
        # missing output
        domain = self.collect_cmd_output("sssctl domain-list", pred=sssd_pred)
        if domain['status'] == 0:
            for domain_name in domain['output'].splitlines():
                self.add_cmd_output("sssctl domain-status -o " + domain_name)
예제 #7
0
파일: grub2.py 프로젝트: xhe123/sos
    def setup(self):
        self.add_copy_spec([
            "/boot/efi/EFI/*/grub.cfg", "/boot/grub2/grub.cfg",
            "/boot/grub2/grubenv", "/boot/grub/grub.cfg",
            "/boot/loader/entries", "/etc/default/grub", "/etc/grub2.cfg",
            "/etc/grub.d"
        ])

        self.add_cmd_output("ls -lanR /boot")
        # call grub2-mkconfig with GRUB_DISABLE_OS_PROBER=true to prevent
        # possible unwanted loading of some kernel modules
        # further, check if the command supports --no-grubenv-update option
        # to prevent removing of extra args in $kernel_opts, and (only) if so,
        # call the command with this argument
        env = {}
        env['GRUB_DISABLE_OS_PROBER'] = 'true'
        grub_cmd = 'grub2-mkconfig'
        co = {'cmd': 'grub2-mkconfig --help', 'output': '--no-grubenv-update'}
        if self.test_predicate(self, pred=SoSPredicate(self, cmd_outputs=co)):
            grub_cmd += ' --no-grubenv-update'
        self.add_cmd_output(grub_cmd, env=env)
예제 #8
0
파일: ipa.py 프로젝트: xhe123/sos
    def setup(self):
        self.pki_tomcat_dir_v4 = "/var/lib/pki/pki-tomcat"
        self.pki_tomcat_dir_v3 = "/var/lib/pki-ca"

        self.pki_tomcat_conf_dir_v4 = "/etc/pki/pki-tomcat/ca"
        self.pki_tomcat_conf_dir_v3 = "/etc/pki-ca"

        # Returns "v3", "v4", or None
        ipa_version = self.check_ipa_server_version()

        if self.ipa_server_installed():
            self._log_debug("IPA server install detected")

            self._log_debug("IPA version is [%s]" % ipa_version)

            self.add_copy_spec([
                "/var/log/ipaserver-install.log",
                "/var/log/ipaserver-kra-install.log",
                "/var/log/ipareplica-install.log",
                "/var/log/ipareplica-ca-install.log",
                "/var/log/ipa-custodia.audit.log"
            ])

        if self.ca_installed():
            self._log_debug("CA is installed: retrieving PKI logs")
            self.retrieve_pki_logs(ipa_version)

        self.add_copy_spec([
            "/var/log/ipaclient-install.log", "/var/log/ipaupgrade.log",
            "/var/log/krb5kdc.log", "/var/log/dirsrv/slapd-*/logs/access",
            "/var/log/dirsrv/slapd-*/logs/errors",
            "/etc/dirsrv/slapd-*/dse.ldif",
            "/etc/dirsrv/slapd-*/schema/99user.ldif", "/etc/hosts",
            "/etc/httpd/alias/*", "/etc/named.*", "/etc/ipa/ca.crt",
            "/etc/ipa/default.conf", "/etc/ipa/kdcproxy/kdcproxy.conf",
            "/etc/ipa/kdcproxy/ipa-kdc-proxy.conf", "/etc/ipa/kdcproxy.conf",
            "/root/.ipa/log/cli.log", "/var/lib/certmonger/requests/[0-9]*",
            "/var/lib/certmonger/cas/[0-9]*", "/var/lib/ipa/ra-agent.pem",
            "/var/lib/ipa/certs/httpd.crt", "/var/kerberos/krb5kdc/kdc.crt",
            "/var/lib/ipa/sysrestore/sysrestore.state",
            "/var/log/ipa/healthcheck/healthcheck.log*"
        ])

        #  Make sure to use the right PKI config and NSS DB folders
        if ipa_version == "v4":
            self.pki_tomcat_dir = self.pki_tomcat_dir_v4
            self.pki_tomcat_conf_dir = self.pki_tomcat_conf_dir_v4
        else:
            self.pki_tomcat_dir = self.pki_tomcat_dir_v3
            self.pki_tomcat_conf_dir = self.pki_tomcat_conf_dir_v3

        self.add_cmd_output("certutil -L -d %s/alias" % self.pki_tomcat_dir)
        self.add_copy_spec("%s/CS.cfg" % self.pki_tomcat_conf_dir)

        self.add_forbidden_path([
            "/etc/pki/nssdb/key*",
            "/etc/dirsrv/slapd-*/key*",
            "/etc/dirsrv/slapd-*/pin.txt",
            "/etc/dirsrv/slapd-*/pwdfile.txt",
            "/etc/httpd/alias/ipasession.key",
            "/etc/httpd/alias/key*",
            "/etc/httpd/alias/pin.txt",
            "/etc/httpd/alias/pwdfile.txt",
            "/etc/named.keytab",
            "%s/alias/key*" % self.pki_tomcat_dir,
            "%s/flatfile.txt" % self.pki_tomcat_conf_dir,
            "%s/password.conf" % self.pki_tomcat_conf_dir,
        ])

        self.add_cmd_output([
            "ls -la /etc/dirsrv/slapd-*/schema/",
            "certutil -L -d /etc/httpd/alias/",
            "pki-server cert-find --show-all",
            "pki-server subsystem-cert-validate ca",
            "klist -ket /etc/dirsrv/ds.keytab",
            "klist -ket /etc/httpd/conf/ipa.keytab",
            "klist -ket /var/lib/ipa/gssproxy/http.keytab"
        ])

        getcert_pred = SoSPredicate(self, services=['certmonger'])

        self.add_cmd_output("getcert list", pred=getcert_pred)

        for certdb_directory in glob("/etc/dirsrv/slapd-*/"):
            self.add_cmd_output("certutil -L -d %s" % certdb_directory)
        return
예제 #9
0
    def setup(self):
        super(Networking, self).setup()
        self.add_copy_spec([
            "/proc/net/", "/etc/nsswitch.conf", "/etc/yp.conf",
            "/etc/inetd.conf", "/etc/xinetd.conf", "/etc/xinetd.d",
            "/etc/host*", "/etc/resolv.conf", "/etc/network*", "/etc/nftables",
            "/etc/sysconfig/nftables.conf", "/etc/nftables.conf",
            "/etc/dnsmasq*", "/sys/class/net/*/device/numa_node",
            "/sys/class/net/*/flags", "/sys/class/net/*/statistics/",
            "/etc/iproute2"
        ])

        self.add_forbidden_path([
            "/proc/net/rpc/use-gss-proxy",
            "/proc/net/rpc/*/channel",
            "/proc/net/rpc/*/flush",
            # Cisco CDP
            "/proc/net/cdp",
            "/sys/net/cdp",
            # Dialogic Diva
            "/proc/net/eicon"
        ])

        self.add_cmd_output("ip -o addr", root_symlink="ip_addr")
        self.add_cmd_output("route -n", root_symlink="route")
        self.add_cmd_output("plotnetcfg")
        # collect iptables -t for any existing table, if we can't read the
        # tables, collect 3 default ones (nat, mangle, filter)
        try:
            ip_tables_names = open("/proc/net/ip_tables_names").read()
        except IOError:
            ip_tables_names = "nat\nmangle\nfilter\n"
        for table in ip_tables_names.splitlines():
            self.collect_iptable(table)
        # collect the same for ip6tables
        try:
            ip_tables_names = open("/proc/net/ip6_tables_names").read()
        except IOError:
            ip_tables_names = "nat\nmangle\nfilter\n"
        for table in ip_tables_names.splitlines():
            self.collect_ip6table(table)

        self.collect_nftables()

        self.add_cmd_output("netstat %s -neopa" % self.ns_wide,
                            root_symlink="netstat")

        self.add_cmd_output([
            "netstat -s",
            "netstat %s -agn" % self.ns_wide,
            "ip route show table all",
            "ip -6 route show table all",
            "ip -4 rule",
            "ip -6 rule",
            "ip -s -d link",
            "ip -d address",
            "ifenslave -a",
            "ip mroute show",
            "ip maddr show",
            "ip -s -s neigh show",
            "ip neigh show nud noarp",
            "biosdevname -d",
            "tc -s qdisc show",
        ])

        # below commands require some kernel module(s) to be loaded
        # run them only if the modules are loaded, or if explicitly requested
        # via --allow-system-changes option
        ip_macsec_show_cmd = "ip -s macsec show"
        macsec_pred = SoSPredicate(self, kmods=['macsec'])
        self.add_cmd_output(ip_macsec_show_cmd, pred=macsec_pred, changes=True)

        ss_cmd = "ss -peaonmi"
        ss_pred = SoSPredicate(self,
                               kmods=[
                                   'tcp_diag', 'udp_diag', 'inet_diag',
                                   'unix_diag', 'netlink_diag',
                                   'af_packet_diag'
                               ],
                               required={'kmods': 'all'})
        self.add_cmd_output(ss_cmd, pred=ss_pred, changes=True)

        # When iptables is called it will load the modules
        # iptables and iptables_filter if they are not loaded.
        # The same goes for ipv6.
        self.add_cmd_output("iptables -vnxL",
                            pred=SoSPredicate(self, kmods=['iptable_filter']))

        self.add_cmd_output("ip6tables -vnxL",
                            pred=SoSPredicate(self, kmods=['ip6table_filter']))

        # Get ethtool output for every device that does not exist in a
        # namespace.
        for eth in listdir("/sys/class/net/"):
            # 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([
                "ethtool " + eth, "ethtool -d " + eth, "ethtool -i " + eth,
                "ethtool -k " + eth, "ethtool -S " + eth, "ethtool -T " + eth,
                "ethtool -a " + eth, "ethtool -c " + eth, "ethtool -g " + eth,
                "ethtool -e " + eth, "ethtool -P " + eth, "ethtool -l " + eth,
                "ethtool --phy-statistics " + eth,
                "ethtool --show-priv-flags " + eth, "ethtool --show-eee " + eth
            ])

        # Collect information about bridges (some data already collected via
        # "ip .." commands)
        self.add_cmd_output([
            "bridge -s -s -d link show", "bridge -s -s -d -t fdb show",
            "bridge -s -s -d -t mdb show", "bridge -d vlan show"
        ])

        if self.get_option("traceroute"):
            self.add_cmd_output("/bin/traceroute -n %s" % self.trace_host)

        # Capture additional data from namespaces; each command is run
        # per-namespace.
        ip_netns = self.collect_cmd_output("ip netns")
        cmd_prefix = "ip netns exec "
        if ip_netns['status'] == 0:
            out_ns = []
            # Regex initialization outside of for loop
            if self.get_option("namespace_pattern"):
                pattern = '(?:%s$)' % '$|'.join(
                    self.get_option("namespace_pattern").split()).replace(
                        '*', '.*')
            for line in ip_netns['output'].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",
                    ns_cmd_prefix + "ip route show table all",
                    ns_cmd_prefix + "iptables-save",
                    ns_cmd_prefix + "netstat %s -neopa" % self.ns_wide,
                    ns_cmd_prefix + "netstat -s",
                    ns_cmd_prefix + "netstat %s -agn" % self.ns_wide,
                ])

                ss_cmd = ns_cmd_prefix + "ss -peaonmi"
                # --allow-system-changes is handled directly in predicate
                # evaluation, so plugin code does not need to separately
                # check for it
                self.add_cmd_output(ss_cmd, pred=ss_pred)

            # 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.exec_cmd(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
                        ])

        return
예제 #10
0
    def collect_nftables(self):
        """ Collects nftables rulesets with 'nft' commands if the modules
        are present """

        self.add_cmd_output("nft list ruleset",
                            pred=SoSPredicate(self, kmods=['nf_tables']))
예제 #11
0
    def collect_ip6table(self, tablename):
        """ Same as function above, but for ipv6 """

        modname = "ip6table_" + tablename
        cmd = "ip6tables -t " + tablename + " -nvL"
        self.add_cmd_output(cmd, pred=SoSPredicate(self, kmods=[modname]))
예제 #12
0
    def setup(self):
        super(Networking, self).setup()
        self.add_copy_spec([
            "/proc/net/",
            "/etc/nsswitch.conf",
            "/etc/yp.conf",
            "/etc/inetd.conf",
            "/etc/xinetd.conf",
            "/etc/xinetd.d",
            "/etc/host*",
            "/etc/resolv.conf",
            "/etc/network*",
            "/etc/nftables",
            "/etc/sysconfig/nftables.conf",
            "/etc/nftables.conf",
            "/etc/dnsmasq*",
            "/sys/class/net/*/device/numa_node",
            "/sys/class/net/*/flags",
            "/sys/class/net/*/statistics/",
            "/etc/iproute2"
        ])

        self.add_forbidden_path([
            "/proc/net/rpc/use-gss-proxy",
            "/proc/net/rpc/*/channel",
            "/proc/net/rpc/*/flush",
            # Cisco CDP
            "/proc/net/cdp",
            "/sys/net/cdp",
            # Dialogic Diva
            "/proc/net/eicon"
        ])

        self.add_cmd_output("ip -o addr", root_symlink="ip_addr")
        self.add_cmd_output("route -n", root_symlink="route")
        self.add_cmd_output("plotnetcfg")
        # collect iptables -t for any existing table, if we can't read the
        # tables, collect 3 default ones (nat, mangle, filter)
        try:
            ip_tables_names = open("/proc/net/ip_tables_names").read()
        except IOError:
            ip_tables_names = "nat\nmangle\nfilter\n"
        for table in ip_tables_names.splitlines():
            self.collect_iptable(table)
        # collect the same for ip6tables
        try:
            ip_tables_names = open("/proc/net/ip6_tables_names").read()
        except IOError:
            ip_tables_names = "nat\nmangle\nfilter\n"
        for table in ip_tables_names.splitlines():
            self.collect_ip6table(table)

        self.collect_nftables()

        self.add_cmd_output("netstat %s -neopa" % self.ns_wide,
                            root_symlink="netstat")

        self.add_cmd_output([
            "netstat -s",
            "netstat %s -agn" % self.ns_wide,
            "ip route show table all",
            "ip -6 route show table all",
            "ip -4 rule",
            "ip -6 rule",
            "ip -s -d link",
            "ip -d address",
            "ifenslave -a",
            "ip mroute show",
            "ip maddr show",
            "ip -s -s neigh show",
            "ip neigh show nud noarp",
            "biosdevname -d",
            "tc -s qdisc show",
        ])

        # below commands require some kernel module(s) to be loaded
        # run them only if the modules are loaded, or if explicitly requested
        # via --allow-system-changes option
        ip_macsec_show_cmd = "ip -s macsec show"
        macsec_pred = SoSPredicate(self, kmods=['macsec'])
        self.add_cmd_output(ip_macsec_show_cmd, pred=macsec_pred, changes=True)

        ss_cmd = "ss -peaonmi"
        ss_pred = SoSPredicate(self, kmods=[
            'tcp_diag', 'udp_diag', 'inet_diag', 'unix_diag', 'netlink_diag',
            'af_packet_diag'
        ], required={'kmods': 'all'})
        self.add_cmd_output(ss_cmd, pred=ss_pred, changes=True)

        # When iptables is called it will load the modules
        # iptables and iptables_filter if they are not loaded.
        # The same goes for ipv6.
        if self.check_ext_prog("grep -q iptable_filter /proc/modules"):
            self.add_cmd_output("iptables -vnxL")
        if self.check_ext_prog("grep -q ip6table_filter /proc/modules"):
            self.add_cmd_output("ip6tables -vnxL")

        # Get ethtool output for every device that does not exist in a
        # namespace.
        for eth in listdir("/sys/class/net/"):
            # 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([
                "ethtool " + eth,
                "ethtool -d " + eth,
                "ethtool -i " + eth,
                "ethtool -k " + eth,
                "ethtool -S " + eth,
                "ethtool -T " + eth,
                "ethtool -a " + eth,
                "ethtool -c " + eth,
                "ethtool -g " + eth,
                "ethtool -e " + eth,
                "ethtool -P " + eth,
                "ethtool -l " + eth,
                "ethtool --phy-statistics " + eth,
                "ethtool --show-priv-flags " + eth,
                "ethtool --show-eee " + eth
            ])

        # Collect information about bridges (some data already collected via
        # "ip .." commands)
        self.add_cmd_output([
            "bridge -s -s -d link show",
            "bridge -s -s -d -t fdb show",
            "bridge -s -s -d -t mdb show",
            "bridge -d vlan show"
        ])

        if self.get_option("traceroute"):
            self.add_cmd_output("/bin/traceroute -n %s" % self.trace_host)

        # Capture additional data from namespaces; each command is run
        # per-namespace.
        ip_netns_file = self.get_cmd_output_now("ip netns")
        cmd_prefix = "ip netns exec "
        if ip_netns_file:
            for namespace in self.get_ip_netns(ip_netns_file):
                ns_cmd_prefix = cmd_prefix + namespace + " "
                self.add_cmd_output([
                    ns_cmd_prefix + "ip address show",
                    ns_cmd_prefix + "ip route show table all",
                    ns_cmd_prefix + "iptables-save",
                    ns_cmd_prefix + "netstat %s -neopa" % self.ns_wide,
                    ns_cmd_prefix + "netstat -s",
                    ns_cmd_prefix + "netstat %s -agn" % self.ns_wide
                ])

                ss_cmd = ns_cmd_prefix + "ss -peaonmi"
                # --allow-system-changes is handled directly in predicate
                # evaluation, so plugin code does not need to separately
                # check for it
                self.add_cmd_output(ss_cmd, pred=ss_pred)

            # 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 +
                                                       "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
                    ])

        return