diff mbox

[Autotest] Autotest: Add utils for OpenVSwitch patch

Message ID 1349266292-13041-1-git-send-email-jzupka@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jiri Zupka Oct. 3, 2012, 12:11 p.m. UTC
pull-request https://github.com/autotest/autotest/pull/569

ForAllxx:
  run object method on every object in list

  ForAll[a,b,c].print()

Signed-off-by: Ji?í Župka <jzupka@redhat.com>
---
 client/shared/base_utils.py  |   81 +++++-
 client/shared/openvswitch.py |  578 ++++++++++++++++++++++++++++++++++++++++++
 client/tests                 |    2 +-
 3 files changed, 646 insertions(+), 15 deletions(-)
 create mode 100644 client/shared/openvswitch.py
diff mbox

Patch

diff --git a/client/shared/base_utils.py b/client/shared/base_utils.py
index 0734742..573b907 100644
--- a/client/shared/base_utils.py
+++ b/client/shared/base_utils.py
@@ -1224,6 +1224,56 @@  def system_output_parallel(commands, timeout=None, ignore_status=False,
     return out
 
 
+class ForAll(list):
+    def __getattr__(self, name):
+        def wrapper(*args, **kargs):
+            return map(lambda o: o.__getattribute__(name)(*args, **kargs), self)
+        return wrapper
+
+
+class ForAllP(list):
+    """
+    Parallel version of ForAll
+    """
+    def __getattr__(self, name):
+        def wrapper(*args, **kargs):
+            threads = []
+            for o in self:
+                threads.append(InterruptedThread(o.__getattribute__(name),
+                                        args=args, kwargs=kargs))
+            for t in threads:
+                t.start()
+            return map(lambda t: t.join(), threads)
+        return wrapper
+
+
+class ForAllPSE(list):
+    """
+    Parallel version of and suppress exception.
+    """
+    def __getattr__(self, name):
+        def wrapper(*args, **kargs):
+            threads = []
+            for o in self:
+                threads.append(InterruptedThread(o.__getattribute__(name),
+                                        args=args, kwargs=kargs))
+            for t in threads:
+                t.start()
+
+            result = []
+            for t in threads:
+                ret = {}
+                try:
+                    ret["return"] = t.join()
+                except Exception:
+                    ret["exception"] = sys.exc_info()
+                    ret["args"] = args
+                    ret["kargs"] = kargs
+                result.append(ret)
+            return result
+        return wrapper
+
+
 def etraceback(prep, exc_info):
     """
     Enhanced Traceback formats traceback into lines "prep: line\nname: line"
@@ -1733,9 +1783,12 @@  def import_site_function(path, module, funcname, dummy, modulefile=None):
     return import_site_symbol(path, module, funcname, dummy, modulefile)
 
 
-def _get_pid_path(program_name):
-    pid_files_dir = GLOBAL_CONFIG.get_config_value("SERVER", 'pid_files_dir',
-                                                   default="")
+def get_pid_path(program_name, pid_files_dir=None):
+    if pid_files_dir is None:
+        pid_files_dir = GLOBAL_CONFIG.get_config_value("SERVER",
+                                                       'pid_files_dir',
+                                                       default="")
+
     if not pid_files_dir:
         base_dir = os.path.dirname(__file__)
         pid_path = os.path.abspath(os.path.join(base_dir, "..", "..",
@@ -1746,25 +1799,25 @@  def _get_pid_path(program_name):
     return pid_path
 
 
-def write_pid(program_name):
+def write_pid(program_name, pid_files_dir=None):
     """
     Try to drop <program_name>.pid in the main autotest directory.
 
     Args:
       program_name: prefix for file name
     """
-    pidfile = open(_get_pid_path(program_name), "w")
+    pidfile = open(get_pid_path(program_name, pid_files_dir), "w")
     try:
         pidfile.write("%s\n" % os.getpid())
     finally:
         pidfile.close()
 
 
-def delete_pid_file_if_exists(program_name):
+def delete_pid_file_if_exists(program_name, pid_files_dir=None):
     """
     Tries to remove <program_name>.pid from the main autotest directory.
     """
-    pidfile_path = _get_pid_path(program_name)
+    pidfile_path = get_pid_path(program_name, pid_files_dir)
 
     try:
         os.remove(pidfile_path)
@@ -1774,18 +1827,18 @@  def delete_pid_file_if_exists(program_name):
         raise
 
 
-def get_pid_from_file(program_name):
+def get_pid_from_file(program_name, pid_files_dir=None):
     """
     Reads the pid from <program_name>.pid in the autotest directory.
 
     @param program_name the name of the program
     @return the pid if the file exists, None otherwise.
     """
-    pidfile_path = _get_pid_path(program_name)
+    pidfile_path = get_pid_path(program_name, pid_files_dir)
     if not os.path.exists(pidfile_path):
         return None
 
-    pidfile = open(_get_pid_path(program_name), 'r')
+    pidfile = open(get_pid_path(program_name, pid_files_dir), 'r')
 
     try:
         try:
@@ -1808,27 +1861,27 @@  def get_process_name(pid):
     return get_field(read_file("/proc/%d/stat" % pid), 1)[1:-1]
 
 
-def program_is_alive(program_name):
+def program_is_alive(program_name, pid_files_dir=None):
     """
     Checks if the process is alive and not in Zombie state.
 
     @param program_name the name of the program
     @return True if still alive, False otherwise
     """
-    pid = get_pid_from_file(program_name)
+    pid = get_pid_from_file(program_name, pid_files_dir)
     if pid is None:
         return False
     return pid_is_alive(pid)
 
 
-def signal_program(program_name, sig=signal.SIGTERM):
+def signal_program(program_name, sig=signal.SIGTERM, pid_files_dir=None):
     """
     Sends a signal to the process listed in <program_name>.pid
 
     @param program_name the name of the program
     @param sig signal to send
     """
-    pid = get_pid_from_file(program_name)
+    pid = get_pid_from_file(program_name, pid_files_dir)
     if pid:
         signal_pid(pid, sig)
 
diff --git a/client/shared/openvswitch.py b/client/shared/openvswitch.py
new file mode 100644
index 0000000..daf4757
--- /dev/null
+++ b/client/shared/openvswitch.py
@@ -0,0 +1,578 @@ 
+import logging, re, os, select, signal
+try:
+    import autotest.common as common
+except ImportError:
+    import common
+from autotest.client import utils, os_dep
+from autotest.client.shared import error
+from autotest.client.shared.base_utils import VersionableClass
+
+
+class ServiceManagerInterface(VersionableClass):
+    def __new__(cls, *args, **kargs):
+        ServiceManagerInterface.master_class = ServiceManagerInterface
+        return super(ServiceManagerInterface, cls).__new__(cls, *args, **kargs)
+
+    @classmethod
+    def get_version(cls):
+        """
+        Get version of ServiceManager.
+        @return: Version of ServiceManager.
+        """
+        return open("/proc/1/comm", "r").read().strip()
+
+    def stop(self, service_name):
+        raise NotImplementedError("Method 'stop' must be"
+                                  " implemented in child class")
+
+
+    def start(self, service_name):
+        raise NotImplementedError("Method 'start' must be"
+                                  " implemented in child class")
+
+
+    def restart(self, service_name):
+        raise NotImplementedError("Method 'restart' must be"
+                                  " implemented in child class")
+
+
+    def status(self, service_name):
+        raise NotImplementedError("Method 'status' must be"
+                                  " implemented in child class")
+
+
+class ServiceManagerSystemD(ServiceManagerInterface, VersionableClass):
+    @classmethod
+    def is_right_version(cls, version):
+        if version == "systemd":
+                return True
+        return False
+
+    def stop(self, service_name):
+        utils.run("systemctl stop %s.service" % (service_name))
+
+
+    def start(self, service_name):
+        utils.run("systemctl start %s.service" % (service_name))
+
+
+    def restart(self, service_name):
+        utils.run("systemctl restart %s.service" % (service_name))
+
+
+    def status(self, service_name):
+        utils.run("systemctl show %s.service" % (service_name))
+
+
+class ServiceManagerSysvinit(ServiceManagerInterface, VersionableClass):
+    @classmethod
+    def is_right_version(cls, version):
+        if version == "init":
+                return True
+        return False
+
+
+    def stop(self, service_name):
+        utils.run("/etc/init.d/%s stop" % (service_name))
+
+
+    def start(self, service_name):
+        utils.run("/etc/init.d/%s start" % (service_name))
+
+
+    def restart(self, service_name):
+        utils.run("/etc/init.d/%s restart" % (service_name))
+
+
+class ServiceManager(ServiceManagerInterface):
+    pass
+
+
+class OpenVSwitchControl(object):
+    """
+    Class select the best matches control class for installed version
+    of OpenVSwitch.
+
+    OpenVSwtich parameters are described in man ovs-vswitchd.conf.db
+    """
+    def __new__(cls, db_path=None, db_socket=None, db_pidfile=None,
+                 ovs_pidfile=None, dbschema=None, install_prefix=None):
+        """
+        Makes initialization of OpenVSwitch.
+
+        @param tmpdir: Tmp directory for save openvswitch test files.
+        @param db_path: Path of OVS databimpoty ase.
+        @param db_socket: Path of OVS db socket.
+        @param db_pidfile: Path of OVS db ovsdb-server pid.
+        @param ovs_pidfile: Path of OVS ovs-vswitchd pid.
+        @param install_prefix: Path where is openvswitch installed.
+        """
+        # if path is None set default path.
+        if not install_prefix:
+            install_prefix = "/"
+        if not db_path:
+            db_path = os.path.join(install_prefix,
+                                   "/etc/openvswitch/conf.db")
+        if not db_socket:
+            db_socket = os.path.join(install_prefix,
+                                     "/var/run/openvswitch/db.sock")
+        if not db_pidfile:
+            db_pidfile = os.path.join(install_prefix,
+                                      "/var/run/openvswitch/ovsdb-server.pid")
+        if not ovs_pidfile:
+            ovs_pidfile = os.path.join(install_prefix,
+                                       "/var/run/openvswitch/ovs-vswitchd.pid")
+        if not dbschema:
+            dbschema = os.path.join(install_prefix,
+                                    "/usr/share/openvswitch/vswitch.ovsschema")
+
+        OpenVSwitchControl.install_prefix = install_prefix
+
+        OpenVSwitchControl.db_path = db_path
+        OpenVSwitchControl.db_socket = db_socket
+        OpenVSwitchControl.db_pidfile = db_pidfile
+        OpenVSwitchControl.ovs_pidfile = ovs_pidfile
+
+        OpenVSwitchControl.dbschema = install_prefix, dbschema
+        os.environ["PATH"] = (os.path.join(install_prefix, "usr/bin:") +
+                              os.environ["PATH"])
+        os.environ["PATH"] = (os.path.join(install_prefix, "usr/sbin:") +
+                              os.environ["PATH"])
+
+        return super(OpenVSwitchControl, cls).__new__(cls)
+
+
+    @staticmethod
+    def convert_version_to_int(version):
+        """
+        @param version: (int) Converted from version string 1.4.0 => int 140
+        """
+        if (isinstance(version, int)):
+            return version
+        try:
+            int_ver = int(version.replace(".", ""))
+        except:
+            raise error.AutotestError("Wrong version format '%s'" % (version))
+        return int_ver
+
+
+    @classmethod
+    def get_version(cls):
+        """
+        Get version of installed OpenVSwtich.
+
+        @return: Version of OpenVSwtich.
+        """
+        version = None
+        try:
+            result = utils.run(os_dep.command("ovs-vswitchd"),
+                               args=["--version"])
+            pattern = "ovs-vswitchd \(Open vSwitch\) (.+)"
+            version = re.search(pattern, result.stdout).group(1)
+        except error.CmdError:
+            logging.debug("OpenVSwitch is not available in system.")
+        return version
+
+
+    def status(self):
+        raise NotImplementedError()
+
+
+    def add_br(self, br_name):
+        raise NotImplementedError()
+
+
+    def del_br(self, br_name):
+        raise NotImplementedError()
+
+
+    def br_exist(self, br_name):
+        raise NotImplementedError()
+
+
+    def list_br(self):
+        raise NotImplementedError()
+
+
+    def add_port(self, br_name, port_name):
+        raise NotImplementedError()
+
+
+    def del_port(self, br_name, port_name):
+        raise NotImplementedError()
+
+
+    def add_port_tag(self, port_name, tag):
+        raise NotImplementedError()
+
+
+    def add_port_trunk(self, port_name, trunk):
+        raise NotImplementedError()
+
+
+    def set_vlanmode(self, port_name, vlan_mode):
+        raise NotImplementedError()
+
+
+    def check_port_in_br(self, br_name, port_name):
+        raise NotImplementedError()
+
+
+class OpenVSwitchControlCli(OpenVSwitchControl, VersionableClass):
+    """
+    Class select the best matches control class for installed version
+    of OpenVSwitch.
+    """
+    def __new__(cls, db_path=None, db_socket=None, db_pidfile=None,
+                ovs_pidfile=None, dbschema=None, install_prefix=None):
+        OpenVSwitchControlCli.master_class = OpenVSwitchControlCli
+        return super(OpenVSwitchControlCli, cls).__new__(cls, db_path,
+                                                         db_socket,
+                                                         db_pidfile,
+                                                         ovs_pidfile,
+                                                         dbschema,
+                                                         install_prefix)
+
+
+class OpenVSwitchControlDB(OpenVSwitchControl, VersionableClass):
+    """
+    Class select the best matches control class for installed version
+    of OpenVSwitch.
+    """
+
+    def __new__(cls, db_path=None, db_socket=None, db_pidfile=None,
+                 ovs_pidfile=None, dbschema=None, install_prefix=None):
+        OpenVSwitchControlDB.master_class = OpenVSwitchControlDB
+        return super(OpenVSwitchControlDB, cls).__new__(cls, db_path,
+                                                        db_socket,
+                                                        db_pidfile,
+                                                        ovs_pidfile,
+                                                        dbschema,
+                                                        install_prefix)
+
+
+class OpenVSwitchControlDB_140(OpenVSwitchControlDB, VersionableClass):
+    """
+    Don't use this class directly. This class is automatically selected by
+    OpenVSwitchControl.
+    """
+    @classmethod
+    def is_right_version(cls, version):
+        """
+        Check condition for select control class.
+
+        @param version: version of OpenVSwtich
+        """
+        if version is not None:
+            int_ver = cls.convert_version_to_int(version)
+            if int_ver <= 140:
+                return True
+        return False
+
+    #TODO: implement database manipulation methods.
+
+
+class OpenVSwitchControlCli_140(OpenVSwitchControlCli, VersionableClass):
+    """
+    Don't use this class directly. This class is automatically selected by
+    OpenVSwitchControl.
+    """
+    @classmethod
+    def is_right_version(cls, version):
+        """
+        Check condition for select control class.
+
+        @param version: version of OpenVSwtich
+        """
+        if version is not None:
+            int_ver = cls.convert_version_to_int(version)
+            if int_ver <= 140:
+                return True
+        return False
+
+
+    def ovs_vsctl(self, parmas, ignore_status=False):
+        return utils.run(os_dep.command("ovs-vsctl"), timeout=10,
+                         ignore_status=ignore_status, verbose=False,
+                         args=["--db=unix:%s" % (self.db_socket)] + parmas)
+
+
+    def status(self):
+        return self.ovs_vsctl(["show"]).stdout
+
+
+    def add_br(self, br_name):
+        self.ovs_vsctl(["add-br", br_name])
+
+
+    def add_fake_br(self, br_name, parent, vlan):
+        self.ovs_vsctl(["add-br", br_name, parent, vlan])
+
+
+    def del_br(self, br_name):
+        try:
+            self.ovs_vsctl(["del-br", br_name])
+        except error.CmdError, e:
+            logging.debug(e.result_obj)
+            raise
+
+
+    def br_exist(self, br_name):
+        try:
+            self.ovs_vsctl(["br-exists", br_name])
+        except error.CmdError, e:
+            if e.result_obj.exit_status == 2:
+                return False
+            else:
+                raise
+        return True
+
+
+    def list_br(self):
+        return self.ovs_vsctl(["list-br"]).stdout.splitlines()
+
+
+    def add_port(self, br_name, port_name):
+        self.ovs_vsctl(["add-port", br_name, port_name])
+
+
+    def del_port(self, br_name, port_name):
+        self.ovs_vsctl(["del-port", br_name, port_name])
+
+
+    def add_port_tag(self, port_name, tag):
+        self.ovs_vsctl(["set", "Port", port_name, "tag=%s" % tag])
+
+
+    def add_port_trunk(self, port_name, trunk):
+        """
+        @param trunk: list of vlans id.
+        """
+        trunk = map(lambda x: str(x), trunk)
+        trunk = "[" + ",".join(trunk) + "]"
+        self.ovs_vsctl(["set", "Port", port_name, "trunk=%s" % trunk])
+
+
+    def set_vlanmode(self, port_name, vlan_mode):
+        self.ovs_vsctl(["set", "Port", port_name, "vlan-mode=%s" % vlan_mode])
+
+
+    def list_ports(self, br_name):
+        return self.ovs_vsctl(["list-ports", br_name]).stdout.splitlines()
+
+
+    def port_to_br(self, port_name):
+        """
+        Return bridge which contain port.
+
+        @param port_name: Name of port.
+        @return: Bridge name or None if there is no bridge which contain port.
+        """
+        bridge = None
+        try:
+            bridge = self.ovs_vsctl(["port-to-br", port_name]).stdout
+        except error.CmdError, e:
+            if e.result_obj.exit_status == 1:
+                pass
+        return bridge
+
+
+class OpenVSwitchSystem(OpenVSwitchControlCli, OpenVSwitchControlDB):
+    """
+    OpenVSwtich class.
+    """
+    def __new__(cls, db_path=None, db_socket=None, db_pidfile=None,
+                 ovs_pidfile=None, dbschema=None, install_prefix=None):
+        return super(OpenVSwitchSystem, cls).__new__(cls, db_path, db_socket,
+                                                db_pidfile, ovs_pidfile,
+                                                dbschema, install_prefix)
+
+
+    def __init__(self, db_path=None, db_socket=None, db_pidfile=None,
+                 ovs_pidfile=None, dbschema=None, install_prefix=None):
+        """
+        Makes initialization of OpenVSwitch.
+
+        @param db_path: Path of OVS database.
+        @param db_socket: Path of OVS db socket.
+        @param db_pidfile: Path of OVS db ovsdb-server pid.
+        @param ovs_pidfile: Path of OVS ovs-vswitchd pid.
+        @param install_prefix: Path where is openvswitch installed.
+        """
+        super(OpenVSwitchSystem, self).__init__(self, db_path, db_socket,
+                                                db_pidfile, ovs_pidfile,
+                                                dbschema, install_prefix)
+
+        self.cleanup = False
+        self.pid_files_path = None
+
+
+    def is_installed(self):
+        """
+        Check if OpenVSwitch is already installed in system on default places.
+
+        @return: Version of OpenVSwtich.
+        """
+        if self.get_version():
+            return True
+        else:
+            return False
+
+
+    def check_db_daemon(self):
+        """
+        Check if OVS daemon is started correctly.
+        """
+        working = utils.program_is_alive("ovsdb-server", self.pid_files_path)
+        if not working:
+            logging.error("OpenVSwitch database daemon with PID in file %s"
+                          " not working.", self.db_pidfile)
+        return working
+
+
+    def check_switch_daemon(self):
+        """
+        Check if OVS daemon is started correctly.
+        """
+        working = utils.program_is_alive("ovs-vswitchd", self.pid_files_path)
+        if not working:
+            logging.error("OpenVSwitch switch daemon with PID in file %s"
+                          " not working.", self.ovs_pidfile)
+        return working
+
+
+    def check_db_file(self):
+        """
+        Check if db_file exists.
+        """
+        exists = os.path.exists(self.db_path)
+        if not exists:
+            logging.error("OpenVSwitch database file %s not exists.",
+                           self.db_path)
+        return exists
+
+
+    def check_db_socket(self):
+        """
+        Check if db socket exists.
+        """
+        exists = os.path.exists(self.db_socket)
+        if not exists:
+            logging.error("OpenVSwitch database socket file %s not exists.",
+                          self.db_socket)
+        return exists
+
+
+    def check(self):
+        return (self.check_db_daemon() and self.check_switch_daemon() and
+                self.check_db_file() and self.check_db_socket())
+
+
+    def init_system(self):
+        """
+        Create new dbfile without any configuration.
+        """
+        sm = ServiceManager()
+        try:
+            if utils.load_module("openvswitch"):
+                sm.restart("openvswitch")
+        except error.CmdError:
+            logging.error("Service OpenVSwitch is probably not"
+                          " installed in system.")
+            raise
+        self.pid_files_path = "/var/run/openvswitch/"
+
+
+    def clean(self):
+        """
+        Empty cleanup function
+        """
+        pass
+
+
+class OpenVSwitch(OpenVSwitchSystem):
+    """
+    OpenVSwtich class.
+    """
+    def __new__(cls, tmpdir, db_path=None, db_socket=None, db_pidfile=None,
+                 ovs_pidfile=None, dbschema=None, install_prefix=None):
+        return super(OpenVSwitch, cls).__new__(cls, db_path, db_socket,
+                                                db_pidfile, ovs_pidfile,
+                                                dbschema, install_prefix)
+
+
+    def __init__(self, tmpdir, db_path=None, db_socket=None, db_pidfile=None,
+                 ovs_pidfile=None, dbschema=None, install_prefix=None):
+        """
+        Makes initialization of OpenVSwitch.
+
+        @param tmpdir: Tmp directory for save openvswitch test files.
+        @param db_path: Path of OVS database.
+        @param db_socket: Path of OVS db socket.
+        @param db_pidfile: Path of OVS db ovsdb-server pid.
+        @param ovs_pidfile: Path of OVS ovs-vswitchd pid.
+        @param install_prefix: Path where is openvswitch installed.
+        """
+        super(OpenVSwitch, self).__init__(db_path, db_socket, db_pidfile,
+                                        ovs_pidfile, dbschema, install_prefix)
+        self.tmpdir = "/%s/openvswitch" % (tmpdir)
+        try:
+            os.mkdir(self.tmpdir)
+        except OSError, e:
+            if e.errno != 17:
+                raise
+
+
+    def init_db(self):
+        utils.run(os_dep.command("ovsdb-tool"), timeout=10,
+                  args=["create", self.db_path, self.dbschema])
+        utils.run(os_dep.command("ovsdb-server"), timeout=10,
+                  args=["--remote=punix:%s" % (self.db_socket),
+                        "--remote=db:Open_vSwitch,manager_options",
+                        "--pidfile=%s" % (self.db_pidfile),
+                        "--detach"])
+        self.ovs_vsctl(["--no-wait", "init"])
+
+
+    def start_ovs_vswitchd(self):
+        utils.run(os_dep.command("ovs-vswitchd"), timeout=10,
+                  args=["--detach",
+                        "--pidfile=%s" % (self.ovs_pidfile),
+                        "unix:%s" % (self.db_socket)])
+
+
+    def init_new(self):
+        """
+        Create new dbfile without any configuration.
+        """
+        self.db_path = os.path.join(self.tmpdir, "conf.db")
+        self.db_socket = os.path.join(self.tmpdir, "db.sock")
+        self.db_pidfile = utils.get_pid_path("ovsdb-server")
+        self.ovs_pidfile = utils.get_pid_path("ovs-vswitchd")
+        self.dbschema = "/usr/share/openvswitch/vswitch.ovsschema"
+
+        self.cleanup = True
+        sm = ServiceManager()
+        #Stop system openvswitch
+        try:
+            sm.stop("openvswitch")
+        except error.CmdError:
+            pass
+        utils.load_module("openvswitch")
+        self.clean()
+        if (os.path.exists(self.db_path)):
+            os.remove(self.db_path)
+
+        self.init_db()
+        self.start_ovs_vswitchd()
+
+
+    def clean(self):
+        logging.debug("Killall ovsdb-server")
+        utils.signal_program("ovsdb-server")
+        if (utils.program_is_alive("ovsdb-server")):
+            utils.signal_program("ovsdb-server", signal.SIGKILL)
+        logging.debug("Killall ovs-vswitchd")
+        utils.signal_program("ovs-vswitchd")
+        if (utils.program_is_alive("ovs-vswitchd")):
+            utils.signal_program("ovs-vswitchd", signal.SIGKILL)
diff --git a/client/tests b/client/tests
index 4ebba12..8f778b1 160000
--- a/client/tests
+++ b/client/tests
@@ -1 +1 @@ 
-Subproject commit 4ebba1264bdcddfe738c109e3fde5395278ba31f
+Subproject commit 8f778b1a42cdd16ca0bc7fb7f8676cda3c9361cc