diff --git a/sos/report/plugins/microovn.py b/sos/report/plugins/microovn.py new file mode 100644 index 000000000..d6505dc13 --- /dev/null +++ b/sos/report/plugins/microovn.py @@ -0,0 +1,40 @@ +# Copyright (C) 2024 Alan Baghumian + +# This file is part of the sos project: https://github.com/sosreport/sos +# +# This copyrighted material is made available to anyone wishing to use, +# modify, copy, or redistribute it subject to the terms and conditions of +# version 2 of the GNU General Public License. +# +# See the LICENSE file in the source distribution for further information. + +from sos.report.plugins import Plugin, UbuntuPlugin + + +class MicroOVN(Plugin, UbuntuPlugin): + """The MicroOVN plugin collects the current status of the microovn + snap. + + It will collect journald logs as well as output from various microovn + commands. + """ + + short_desc = 'MicroOVN Snap' + plugin_name = "microovn" + profiles = ('network', 'virt') + + packages = ('microovn', ) + commands = ('microovn', ) + + def setup(self): + self.add_journal(units="snap.microovn.*") + + microovn_subcmds = [ + 'cluster list', + 'status', + 'certificates list', + '--version' + ] + self.add_cmd_output([ + f"microovn {subcmd}" for subcmd in microovn_subcmds + ]) diff --git a/sos/report/plugins/ovn_central.py b/sos/report/plugins/ovn_central.py index 8144dd44e..0040c2806 100644 --- a/sos/report/plugins/ovn_central.py +++ b/sos/report/plugins/ovn_central.py @@ -1,4 +1,5 @@ # Copyright (C) 2018 Mark Michelson +# Copyright (C) 2024 Alan Baghumian # This file is part of the sos project: https://github.com/sosreport/sos # @@ -26,14 +27,15 @@ class OVNCentral(Plugin): profiles = ('network', 'virt') containers = ('ovn-dbs-bundle.*', 'ovn_cluster_north_db_server') container_name = "" - ovn_nbdb_sock_path = "" - ovn_sbdb_sock_path = "" - ovn_sock_path = "" + ovn_nbdb_socket = "" + ovn_sbdb_socket = "" + ovn_socket = "" ovn_controller_sock_regex = "" ovn_northd_sock_regex = "" + pfx = "" def _find_sock(self, path, regex_name): - _sfile = os.path.join(path, regex_name) + _sfile = self.path_join(path, regex_name) if self.container_name: res = self.exec_cmd(f"ls {path}", container=self.container_name) if res['status'] != 0 or '\n' not in res['output']: @@ -45,11 +47,11 @@ def _find_sock(self, path, regex_name): pattern = re.compile(regex_name) for filename in res['output'].split('\n'): if pattern.match(filename): - return os.path.join(path, filename) + return self.path_join(path, filename) # File not found, return the regex full path return _sfile - def get_tables_from_schema(self, filename, skip=None): + def get_tables_from_schema(self, filename, skip=[]): """ Get tables from schema """ if self.container_name: cmd = f"cat {filename}" @@ -84,12 +86,12 @@ def get_tables_from_schema(self, filename, skip=None): self._log_error(f"DB schema {filename} has no 'tables' key") return None - def add_database_output(self, tables, cmds, ovn_cmd): + def add_database_output(self, tables, ovn_cmd): """ Collect OVN database output """ - if not tables: - return - for table in tables: - cmds.append(f'{ovn_cmd} list {table}') + if tables: + return [f"{ovn_cmd} list {table}" for table in tables] + else: + return None def setup(self): # check if env is a clustered or non-clustered one @@ -106,6 +108,7 @@ def setup(self): self.path_join('/var/lib/openvswitch/ovn', pidfile), self.path_join('/usr/local/var/run/openvswitch', pidfile), self.path_join('/run/openvswitch/', pidfile), + self.path_join('/var/snap/microovn/common/run/ovn', pidfile), ]) if ovs_rundir: @@ -116,52 +119,71 @@ def setup(self): else: self.add_copy_spec("/var/log/ovn/*.log") - ovn_controller_sock_path = self._find_sock( - self.ovn_sock_path, self.ovn_controller_sock_regex) + ovn_controller_socket = self._find_sock( + self.ovn_socket, self.ovn_controller_sock_regex) - northd_sock_path = self._find_sock(self.ovn_sock_path, - self.ovn_northd_sock_regex) + northd_socket = self._find_sock(self.ovn_socket, + self.ovn_northd_sock_regex) # ovsdb nb/sb cluster status commands - cstat = "cluster/status" - self.add_cmd_output([ - f"ovs-appctl -t {self.ovn_nbdb_sock_path} {cstat} OVN_Northbound", - f"ovs-appctl -t {self.ovn_sbdb_sock_path} {cstat} OVN_Southbound", - f"ovn-appctl -t {northd_sock_path} status", - f"ovn-appctl -t {northd_sock_path} debug/chassis-features-list", - f"ovn-appctl -t {ovn_controller_sock_path} connection-status", - ], foreground=True, container=self.container_name, timeout=30 - ) + cs = "cluster/status" + cmds = [] + pfx = self.pfx + + appctl_cmds = [ + f"{pfx}ovs-appctl -t {self.ovn_nbdb_socket} {cs} OVN_Northbound", + f"{pfx}ovs-appctl -t {self.ovn_sbdb_socket} {cs} OVN_Southbound", + f"{pfx}ovn-appctl -t {northd_socket} status", + f"{pfx}ovn-appctl -t {ovn_controller_socket} connection-status", + ] + + self.add_cmd_output(appctl_cmds, foreground=True, + container=self.container_name, timeout=30) + + # MicroOVN currently does not support this + if not pfx: + dfl = "debug/chassis-features-list" + self.add_cmd_output(f"{pfx}ovn-appctl -t {northd_socket} {dfl}", + foreground=True, + container=self.container_name, timeout=30) # Some user-friendly versions of DB output + nolo = "--no-leader-only" nbctl_cmds = [ - 'ovn-nbctl --no-leader-only show', - 'ovn-nbctl --no-leader-only get-ssl', - 'ovn-nbctl --no-leader-only get-connection', + f"{pfx}ovn-nbctl {nolo} show", + f"{pfx}ovn-nbctl {nolo} get-ssl", + f"{pfx}ovn-nbctl {nolo} get-connection", ] + self.add_cmd_output(nbctl_cmds, foreground=True, + container=self.container_name, timeout=30) + sbctl_cmds = [ - 'ovn-sbctl --no-leader-only show', - 'ovn-sbctl --no-leader-only lflow-list', - 'ovn-sbctl --no-leader-only get-ssl', - 'ovn-sbctl --no-leader-only get-connection', + f"{pfx}ovn-sbctl {nolo} show", + f"{pfx}ovn-sbctl {nolo} lflow-list", + f"{pfx}ovn-sbctl {nolo} get-ssl", + f"{pfx}ovn-sbctl {nolo} get-connection", ] - # backward compatibility - for path in ['/usr/share/openvswitch', '/usr/share/ovn']: - nb_tables = self.get_tables_from_schema(self.path_join( - path, 'ovn-nb.ovsschema')) - self.add_database_output(nb_tables, nbctl_cmds, - 'ovn-nbctl --no-leader-only') + self.add_cmd_output(sbctl_cmds, foreground=True, + container=self.container_name, timeout=30) - cmds = nbctl_cmds - - for path in ['/usr/share/openvswitch', '/usr/share/ovn']: - sb_tables = self.get_tables_from_schema(self.path_join( - path, 'ovn-sb.ovsschema'), ['Logical_Flow']) - self.add_database_output(sb_tables, sbctl_cmds, - 'ovn-sbctl --no-leader-only') - cmds += sbctl_cmds + # backward compatibility + for path in ['/usr/share/openvswitch', '/usr/share/ovn', + '/snap/microovn/current/share/ovn']: + if self.path_exists(self.path_join(path, 'ovn-nb.ovsschema')): + nb_tables = self.get_tables_from_schema(self.path_join( + path, 'ovn-nb.ovsschema')) + cmds.extend(self.add_database_output(nb_tables, + f"{pfx}ovn-nbctl {nolo}")) + + for path in ['/usr/share/openvswitch', '/usr/share/ovn', + '/snap/microovn/current/share/ovn']: + if self.path_exists(self.path_join(path, 'ovn-sb.ovsschema')): + sb_tables = self.get_tables_from_schema(self.path_join( + path, 'ovn-sb.ovsschema'), ['Logical_Flow']) + cmds.extend(self.add_database_output(sb_tables, + f"{pfx}ovn-sbctl {nolo}")) # If OVN is containerized, we need to run the above commands inside # the container. Removing duplicates (in case there are) to avoid @@ -182,9 +204,10 @@ def setup(self): "/var/lib/openvswitch", "/var/lib/ovn/etc", "/var/lib/ovn", + "/var/snap/microovn/common/data/central/db", ]: dbfilepath = self.path_join(path, dbfile) - if os.path.exists(dbfilepath): + if self.path_exists(dbfilepath): self.add_copy_spec(dbfilepath) self.add_cmd_output( f"ls -lan {dbfilepath}", foreground=True) @@ -197,18 +220,28 @@ def setup(self): class RedHatOVNCentral(OVNCentral, RedHatPlugin): packages = ('openvswitch-ovn-central', 'ovn.*-central', ) - ovn_nbdb_sock_path = '/var/run/openvswitch/ovnnb_db.ctl' - ovn_sbdb_sock_path = '/var/run/openvswitch/ovnsb_db.ctl' - ovn_sock_path = '/var/run/openvswitch' + ovn_nbdb_socket = '/var/run/openvswitch/ovnnb_db.ctl' + ovn_sbdb_socket = '/var/run/openvswitch/ovnsb_db.ctl' + ovn_socket = '/var/run/openvswitch' ovn_controller_sock_regex = 'ovn-controller.*.ctl' ovn_northd_sock_regex = 'ovn-northd.*.ctl' class DebianOVNCentral(OVNCentral, DebianPlugin, UbuntuPlugin): - packages = ('ovn-central', ) - ovn_nbdb_sock_path = '/var/run/ovn/ovnnb_db.ctl' - ovn_sbdb_sock_path = '/var/run/ovn/ovnsb_db.ctl' - ovn_sock_path = '/var/run/ovn' + packages = ('ovn-central', 'microovn', ) + + def setup(self): + if self.path_exists('/snap/bin/microovn'): + self.ovn_socket = '/var/snap/microovn/common/run/ovn' + self.ovn_nbdb_socket = f"{self.ovn_socket}/ovnnb_db.ctl" + self.ovn_sbdb_socket = f"{self.ovn_socket}/ovnsb_db.ctl" + self.pfx = 'microovn.' + else: + self.ovn_socket = '/var/run/ovn' + self.ovn_nbdb_socket = '/var/run/ovn/ovnnb_db.ctl' + self.ovn_sbdb_socket = '/var/run/ovn/ovnsb_db.ctl' + super().setup() + ovn_controller_sock_regex = 'ovn-controller.*.ctl' ovn_northd_sock_regex = 'ovn-northd.*.ctl'