linux发行版检测

Autotest有个功能,就是让测试清晰了解到它运行在什么样的发行版上. 这个功能是由probe类群的实现和注册实现的. 这些probe类可以检查运行的系统的信息,比如发行版的release文件,二进制信息(如包管理)等.

快速检查发行版

autotest.client.shared.distro 模块提供一些APIS,最简单的就是使用detect(). 它的用法简单命了:

    from autotest.client.shared import distro
    detected_distro = distro.detect()

这样就可以返回发行版检测的结果,但是不太适用于UNKNOWN_DISIRO.

  • name
  • version
  • release
  • arch

例如:

>>>detected_distro = distro.detect()
>>>print detected_distro.name
redhat

未知发行版

当检测机制不能检测到发行版,仍会返回一个LinuxDistro实例,但是它的name,version等信息比较特殊.

 autotest.clientshared.distro.UNKNOWN_DISIRO
 =<LinuxDistro: name=unnknown, version=0, realease=0, arch=unknown>

意味着,这个发行版不能找到对应的匹配信息.

编写一个发行版probe

为目标发行版编写一个probe最简单的方式就是使用现有的Probe类的功能. 如果,不打算采用Probe的话,也应该尽量继承probe类,或则提供类似的接口.

检查发行版的名字

最简单的探针就是查看存在的文件并返回发行版的名字.

    class ReadHatProbe(Probe):
        CHECK_FILE = '/etc/redhat-realease'
        CHECK_FILE_DISTRO_NAME = 'redhat'

如果要使用probe,需要先注册:

    from autotest.client.shared import distro
    distro.register_probe(RedHatProbe)

这是一个有效的例子,但只有发行版的名字,通常你的目标应该是更多的信息,如版本号。

侦测发行版的名字和版本

如果,你需要侦测发行版的版本信息,可以使用Probe类的 Probe.CHECK_VERSION_REGEX

Probe.CHECK_VERSION_REGEX=None

注册自己的probes

Autotest不仅仅可以使用自带的probes,而且可以添加自己的probes用于系统的侦测. 注册的简单方式就剩调用register_probe():

autotest.client.shared.distro.register_probe(probe_class)

注意,要注册的自己的probes必须是probe的子类.

API参考

LinuxDistro

class autotest.client.shared.distro.LinuxDistro(name, version, release, arch) 源码

收集linux发行版信息的简单方式.

Probe

class autotest.client.shared.distro.Probe 源码

CHECK_FILE=None

CHECK_FILE_CONTAINS=None

CHECK_FILE_DISTRO_NAME =None

CHECK_VERSION_REGEX = None

Check_name_for_file()

check_name_for_file_contains()

check_release()

check_version()

get_distro()

name_for_file()

name_for_file_contains()

release()

version()

register_probe()

autotest.client.shared.distro.register_probe(probe_class) 源码

注册probe

detect()

autotest.client.shared.distro.detect() 源码

尝试检测这台机器上的Linux发行版本

Source code for autotest.client.shared.distro

    """
    This module provides the client facilities to detect the Linux Distribution
    it's running under.

    This is a replacement for the get_os_vendor() function from the utils modules.
    """

    import os
    import platform
    import re


    __all__ = ['LinuxDistro',
               'UNKNOWN_DISTRO_NAME',
               'UNKNOWN_DISTRO_VERSION',
               'UNKNOWN_DISTRO_RELEASE',
               'UNKNOWN_DISTRO_ARCH',
               'Probe',
               'register_probe',
               'detect']
    # [__all__用法]()

    # pylint: disable=R0903

LinuxDistro :

    class LinuxDistro(object):
        '''
        Simple collection of infomation for a Linux Distribution
        '''

        def __init__(self, name, version, release, arch):
            '''
            Initalizes a new Linux Distro
            :param name: 一个简单的区别于其他发型版的名字
            :type name : 字符
            :parm vesion:发行版的主版本.
            :type vesion: 字符
            :param release: 发行版的发型号或子版本.
            :type vesion:字符
            :parm arch: 发行版的平台架构信息,如interl/amd 32bit/64bit
            :type arch: 字符
            '''
            self.name = name
            self.version = version
            self.release = release
            self.arch = arch

        def __repr__(self):  # [Difference between __str__ and __repr__ in Python](http://stackoverflow.com/questions/1436703/difference-between-str-and-repr-in-python)
            return '<LinuxDistro: name=%s, version=%s, release=%s, arch=%s>' % (
                self.name, self.version, self.release, self.arch)


    UNKNOWN_DISTRO_NAME = 'unknown'
    UNKNOWN_DISTRO_VERSION = 0
    UNKNOWN_DISTRO_RELEASE = 0
    UNKNOWN_DISTRO_ARCH = 'unknown'   # 定义未知发行版默认信息

    #: 未知发行版,反馈以下信息
    UNKNOWN_DISTRO = LinuxDistro(UNKNOWN_DISTRO_NAME,
                                 UNKNOWN_DISTRO_VERSION,
                                 UNKNOWN_DISTRO_RELEASE,
                                 UNKNOWN_DISTRO_ARCH)

Probe :

    class probe(object):

        '''
        探测机器信息并且确认是否存在的发行版
        '''
        #:指定运行机器上发行版中的文件.
        CHECK_FILE = None

        #:设置指向文件的检查内容,默认为None,只检查是否存在
        CHECK_FILE_CONTAINS = None

        #:如果文件指定,指定发行版名字
        CHECK_FILE_DISTRO_NAME = None

        #:指定发行版版本
        CHECK_VERSION_REGEX = None

        def __init__(self):
            self.score = 0

        def check_name_for_file(self): 
            '''
            查找一个文件并返回distro.确认是否指定了特定文件
            '''
            if self.CHECK_FILE is None:
                return False

            if self.CHECK_FILE_DISTRO_NAME is None:
                return False

            return True

        def name_for_file(self):
            '''
            获取distro名称,如果"CHECK_FILE"设置并且存在
            '''
            if self.check_name_for_file():
                if os.path.exists(self.CHECK_FILE):
                    return self.CHECK_FILE_DISTRO_NAME

        def check_name_for_file_contains(self):
            '''
            该类查找text并返回distro.
            The conditions that must be true include the file that identifies the
            distro file being set (:attr:`CHECK_FILE`), the text to look for
            inside the distro file (:attr:`CHECK_FILE_CONTAINS`) and the name
            of the distro to be returned (:attr:`CHECK_FILE_DISTRO_NAME`)
            '''
            if self.CHECK_FILE is None:
                return False

            if self.CHECK_FILE_CONTAINS is None:
                return False

            if self.CHECK_FILE_DISTRO_NAME is None:
                return False

            return True

        def name_for_file_contains(self):
            '''
             获取distro如果CHECK_FILE指定并且有效
            '''
            if self.check_name_for_file_contains():
                if os.path.exits(self.CHECK_FILE):
                    for line in open(self.CHECK_FILE).readlines():
                        if self.CHECK_FILE_CONTAINS in line:
                            return self.CHECK_FILE_DISTRO_NAME

        def check_version(self):
            '''
             检查在文件中是否找到regex并返回distro
            '''
            if self.CHECK_FILE is None:
                return False

             if self.CHECK_VERSION_REGEX is None:
                 return False

             return True

        def _get_version_match(self):
            '''
            返回匹配备注文件中的版本信息
            '''
            if self.check_version():
                if os.patch.exists(self.CHECK_FILE):
                    version_file_content = open(self.CHECK_FILE).read()
                else:
                    return None

                return self.CHECK_VERSION_REGEX.match(version_file_content)

         def version(self):
             '''
             返回distro的版本信息
             '''
             version = UNKNOWN_DISTRO_VERSION
             match = self._get_version_match()
             if match is not None:
                 if match.groups() > 0:
                     version = match.groups()[0]
             return version

        def check_release(self):
            '''
            检查是否存在符合条件的版本号
            '''
            return (self.check_version() and
                    self.CHECK_VERSION_REGEX.groups > 1)

        def release(self):
            '''
             返回 distro的版本号
            '''
             release = UNKNOWN_DISTRO_RELEASE
             match = self._get_version_match()
             if match is not None:
                 if match.groups() > 1:
                     release = match.groups()[1]
             return release

        def get_distro(self):
            '''
            返回 class:'LinuxDistro' probe detected
            '''
            name = None
            version = UNKNOWN_DISTRO_VERSION
            release = UNKNOWN_DISTRO_RELEASE
            arch = UNKNOWN_DISTRO_ARCH

            distro = None

            if self.check_name_for_file():
                name = self.name_for_file():
                self.score += 1

            if self.check_name_for_file_contains():
                name = self.name_for_file_contains()
                self.score += 1

            if self.check_version():
                version = self.version()
                self.score += 1

            if self.check_release():
                release = self.release()
                 self.score += 1

            # 实在想不到比这更好的方式
            arch = os.uname()[4]

            # 名字是首先要侦测的.它可以告诉我们是哪个发行版.
            if name is not None:
                distro = LinuxDistro(name, version, release, arch)
            else:
                distro = UNKNOWN_DISTRO

            return distro

    class StdLibProbe(Probe):
        '''
         Probe是使用python库内建的probe.
         这个Probe得分比较低,作为备用probe.
        '''

        def get_distro(self):
            name = None
            version = UNKNOWN_DISTRO_VERSION
            realease = UNKONWN_DISTRO_RELEASE
            arch = UNKONWN_DISTRO_ARCH

            d_name, d_version_release, d_codename = platform.dist()
            if d_name:
                name = d_name

            if '.' in d_version_release:
                d_version, d_release = d_version_release.split('.', 1)
                version = d_version
                release = d_release
            else:
                version = d_version_release

             arch = os.uname()[4]

             if name is not None:
                 distro = LinuxDistro(name, version, release, arch)
             else:
                 distro = UNKNOWN_DISTRO

             return distro

    class RedHatProbe(Probe)

        '''
        红帽发行版版本检查
        '''
        CHECK_FILE = '/etc/redhat=release'
        CHECK_FILE_CONTAINS = 'Red Hat'
        CHECK_FILE_DISTRO_NAME = 'redhat'
        CHECK_VERSION_REGEX = re.compile(
            r'Red Hat Enterprise Linux Server release(\d{1,2})\.(\d{1,2}).*')

    class CentosProbe(RedHatProbe):
        '''
        Centos系统检测
        '''

        CHECK_FILE = '/etc/redhat-release'
        CHECK_FILE_CONTAINS = 'CentOS'
        CHECK_FILE_DISTRO_NAME = 'centos'
        CHECK_VERSION_REGEX = re.compile(r'CentOS release(\d{1,2})\.(\d{1,2}).*')

    class FedoraProbe(RedHatProbe):

        '''
        Probe with version checks for Fedora systems
        '''
        CHECK_FILE = '/etc/fedora-release'
        CHECK_FILE_CONTAINS = 'Fedora'
        CHECK_FILE_DISTRO_NAME = 'fedora'
        CHECK_VERSION_REGEX = re.compile(r'Fedora release (\d{1,2}).*')


    class DebianProbe(Probe):

        '''
        Simple probe with file checks for Debian systems
        '''
        CHECK_FILE = '/etc/debian-version'
        CHECK_FILE_DISTRO_NAME = 'debian'


    class UbuntuProbe(Probe):

        '''
        Simple probe with file checks for Ubuntu systems
        '''
        CHECK_FILE = '/etc/os-release'
        CHECK_FILE_CONTAINS = 'Ubuntu'
        CHECK_FILE_DISTRO_NAME = 'ubuntu'
        CHECK_VERSION_REGEX = re.compile(r'VERSION_ID="(\d+.\d+)"')


    class SuseProbe(Probe):
        CHECK_FILE = '/etc/SuSE-release'
        CHECK_FILE_DISTRO_NAME = 'sles'
        CHECK_VERSION_REGEX = re.compile(r'SUSE.*\nVERSION = (.*)\nPATCHLEVEL = (.*)')


    #: 已注册probes列表
    REGISTERED_PROBES = []

register_probe :

    register_probe():
        def register_probe(probe_class): 
        '''
        注册probe
        '''
        if probe_class not in REGISTERED_PROBES:
            REGISTERED_PROBES.appen(probe_class)

    register_probe(RedHatProbe)
    register_probe(CentosProbe)
    register_probe(FedoraProbe)
    register_probe(DebianProbe)
    register_probe(UbuntuProbe)
    register_probe(SuseProbe)
    register_probe(StdLibProbe)

detect :

    def detect():
        '''
        尝试在机器上侦测发行版
      '''
        results = []

        for probe_class in REGISTERED_PROBES:
            probe_instance = probe_class()
            didtro_result = probe_instance.get_distro()
            if distro_result is not UNKNOWN_DISTRO:
                results.append((distro_result, probe_instance))

        results.sort(key=lambda t: t[1].score)
        if len(results) > 0:
            distro = results[-1][0]
        else:
            distro = UNKNOWN_DISTRO
        return dostro

    class Spec(object):
        '''
        发行版最低发行要求
     '''
        def __init__(self, name, min_version=None,     min_release=None, arch=None):
            self.name = name
            self.min_version = min_version
            self.min_release = min_release
            self.arch = arch

Top^

上一篇Autotest:Autotest-Using and developing job profilers 下一篇Autotest:Autotest-others>>>

by 李鹏