zoukankan      html  css  js  c++  java
  • openstack 使用cloud init 和 console-log, nbd或者libguestfs 获取VM中的硬件信息。

    以获取PCI的信息为例。

    基本代码:

    pci.py

    import base64
    import guestfs
    from functools import partial
    import os
    import six
    import stat
    import subprocess
    import tempfile
    import time
    import xml.etree.ElementTree as ET
    
    from oslo_utils import encodeutils
    from tempest import config
    from tempest_lib.common.utils import data_utils
    
    def shell_command(cmd, log=False):
        # cmd = ['sudo', 'ip', 'netns', 'exec', ns, 'ssh', "%s@%s" %(name, ip),
        # "'%s;ifconfig eth1 %s/24'" % (name ip)]
        p = subprocess.Popen(
            cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        out, err = p.communicate()
        if log:
            print out
            print err
            if len(err):
                return False
        return out
    
    
    VM_MOUNT_POINT = "/mnt"
    PCI_PATH = "/pci.info"
    RC_LOCAL = "/etc/rc.local"
    USER_DATA = ['#!/bin/sh -e',
                 '# mount -a',
                 'mount /dev/vdb %s' % VM_MOUNT_POINT,
                 'touch %s%s' % (VM_MOUNT_POINT, PCI_PATH),
                 'lspci > %s%s' % (VM_MOUNT_POINT, PCI_PATH),
                 '# umount /mnt/'
                 'exit 0']
    
    
    PCIINFO_DELIMITER = "*" * 40 + "%s" + "*" * 40
    PCIINFO_DELIMITER_BEGIN = PCIINFO_DELIMITER % "PCI INFO BEGIN"
    PCIINFO_DELIMITER_END = PCIINFO_DELIMITER % "PCI INFO END"
    
    CONSOLE_DATA = ['#!/bin/sh -e',
                    'sudo echo "%s"' % PCIINFO_DELIMITER_BEGIN,
                    'sudo lspci',
                    'sudo echo "%s"'  % PCIINFO_DELIMITER_END,
                    'exit 0']
    
    def gen_rc_local_file(pci_path=PCI_PATH):
        """please remove the file: os.remove(p)
           print gen_rc_local()
        """
        l, p = tempfile.mkstemp("local", "rc")
        f = open(p, 'w+b')
        f.writelines(['#!/bin/sh -e
    ',
                      'mount -a
    ',
                      'touch %s%s
    ' % (VM_MOUNT_POINT, pci_path),
                      'lspci > %s%s
    ' % (VM_MOUNT_POINT, pci_path),
                      'umount /mnt/
    '
                      'exit 0
    '])
        os.chmod(p, stat.S_IRWXU + stat.S_IXGRP + stat.S_IXOTH)
        f.close()
        return p, pci_path
    
    
    def gen_rc_local_dict(pci_path=PCI_PATH):
        """
        usage: personality = {}
               personality.append({
                   'path': filepath,
                   'contents': cont,
               })
    
        """
        data = ['#!/bin/sh -e',
                'mount -a',
                'touch %s%s' % (VM_MOUNT_POINT, pci_path),
                'lspci > %s%s' % (VM_MOUNT_POINT, pci_path),
                'cd ~',
                'umount /mnt/',
                'exit 0']
        data = "
    ".join(data)
        if six.PY3 and isinstance(data, str):
            data = data.encode('utf-8')
        cont = base64.b64encode(data).decode('utf-8')
        return cont
    
    
    def gen_user_data(userdata=USER_DATA):
        if hasattr(userdata, 'read'):
            userdata = userdata.read()
        # NOTE(melwitt): Text file data is converted to bytes prior to
        # base64 encoding. The utf-8 encoding will fail for binary files.
        if six.PY3:
            try:
                userdata = userdata.encode("utf-8")
            except AttributeError:
                # In python 3, 'bytes' object has no attribute 'encode'
                pass
        else:
            try:
                userdata = encodeutils.safe_encode(userdata)
            except UnicodeDecodeError:
                pass
    
        userdata_b64 = base64.b64encode(userdata).decode('utf-8')
        return userdata_b64
    
    
    def gen_etc_fstab():
        """
        usage: personality = {}
               personality.append({
                   'path': filepath,
                   'contents': cont,
               })
    
        """
        data = ["/dev/root  /         auto     rw,noauto                 0 1",
                "proc       /proc     proc     defaults                  0 0",
                "devpts     /dev/pts  devpts   defaults,gid=5,mode=620   0 0",
                "tmpfs      /dev/shm  tmpfs    mode=0777                 0 0",
                "sysfs      /sys      sysfs    defaults                  0 0",
                "tmpfs      /run      tmpfs    rw,nosuid,relatime,size=200k,mode=755 0 0",
                "/dev/vdb    /mnt/ auto    defaults                0 0"]
    
        data = "
    ".join(data)
        if six.PY3 and isinstance(data, str):
            data = data.encode('utf-8')
        cont = base64.b64encode(data).decode('utf-8')
        return cont
    
    def get_pci_info(disk, pci_path=PCI_PATH):
        """please remove the dir: os.rmdir(p)
        mount the disk by guestfs and get the pci info.
        need:
        $ sudo chmod g+rw /boot/vmlinuz-/boot/vmlinuz-`uname -r`
        $ sudo usermod -a -G root jenkins
        need to install these 2 packages
        $ sudo apt-get install libguestfs-tools
        $ sudo apt-get install python-guestfs
        need to add use to kvm group
        $ sudo usermod -a -G kvm jenkins
        or
        $ sudo chmod 0666 /dev/kvm
        ref http://libguestfs.org/guestfs-python.3.html
        for debug:
        $ export LIBGUESTFS_DEBUG=1
        $ export LIBGUESTFS_TRACE=1
        ref http://libguestfs.org/guestfs-faq.1.html#debugging-libguestfs
        """
        p = tempfile.mkdtemp("guestfs", "mount")
        g = guestfs.GuestFS(python_return_dict=True)
        # g.add_drive_opts(disk, format="qcow2", readonly=1)
        g.add_drive_opts(disk, readonly=1)
        g.launch()
        g.mount('/dev/sda', '/')
        return g.read_lines(pci_path)
    
    
    def nbd_mount(f, disk, path=PCI_PATH):
        """please remove the dir: os.rmdir(p)
        mount the disk by guestfs and get the pci info.
        need:
        $ sudo rmmod nbd
        $ sudo modprobe nbd max_part=16
        ref https://en.wikibooks.org/wiki/QEMU/Images
        ref https://blogs.gnome.org/muelli/2010/03/mounting-qemu-qcow2-image-using-nbd/
        """
        mount_point = "/mnt/nbd"
        cmd = ["sudo", "modinfo", "nbd"]
        out = shell_command(cmd)
        if "modinfo: ERROR:" in out:
            cmd = ["sudo", "modprobe", "nbd", "max_part=16"]
            shell_command(cmd)
    
        if not os.path.exists(mount_point):
            cmd = ["sudo", "mkdir", mount_point]
            shell_command(cmd)
    
        if os.path.ismount(mount_point):
            cmd = ["sudo", "umount", mount_point]
            shell_command(cmd)
    
        cmd = ["sudo", "qemu-nbd", "-d", "/dev/nbd0"]
        shell_command(cmd)
    
        cmd = ["sudo", "killall", "qemu-nbd"]
        shell_command(cmd)
    
        # cmd = ["sudo", "qemu-nbd", "-r", "-c", "/dev/nbd0", disk]
        cmd = ["sudo", "qemu-nbd", "-c", "/dev/nbd0", disk]
        shell_command(cmd)
    
        cmd = ["sudo", "mount", "/dev/nbd0", mount_point]
        shell_command(cmd)
    
        if not os.path.ismount(mount_point):
            cmd = ["sudo", "qemu-nbd", "-d", "/dev/nbd0"]
            shell_command(cmd)
            raise Exception("Can't mount the VM disk!")
    
        out = f(mount_point, path)
    
        cmd = ["sudo", "umount", mount_point]
        shell_command(cmd)
    
        cmd = ["sudo", "qemu-nbd", "-d", "/dev/nbd0"]
        shell_command(cmd)
        return out
    
    
    def cat_file(mount, pci_path):
        cmd = ["sudo", "cat", mount + pci_path]
        pci_info = shell_command(cmd, True)
        if pci_info is False:
            return pci_info
        return pci_info.splitlines()
    
    
    get_pci_info_by_nbd = partial(nbd_mount, cat_file)
    
    
    def x_file(mount, rc_path):
        cmd = ["sudo", "chmod", "a+x", mount + rc_path]
        out = shell_command(cmd)
        return out
    
    rc_local_add_x = partial(nbd_mount, x_file)
    
    
    def get_vda_path(xml):
        # tree = ET.parse('/etc/libvirt/qemu/instance-0000001f.xml')
        # root = tree.getroot()
        root = ET.fromstring(xml)
        disks = root.findall("./devices/disk[@device='disk'][@type='file']")
        for d in disks:
            t = d.find("target")
            if t.attrib.get("dev") == "vda":
                return d.find("./source").get("file")
    
    def get_config_drive_path(xml):
        # tree = ET.parse('/etc/libvirt/qemu/instance-0000001f.xml')
        # root = tree.getroot()
        root = ET.fromstring(xml)
        disks = root.findall("./devices/disk[@device='disk'][@type='file']")
        for d in disks:
            f = d.find("./source").get("file")
            if "disk.config" in f:
                return f
    
    
    def get_pci_output(get_console_output, server_id):
        output = get_console_output(server_id, -1)['output']
        lines = output.split('
    ')
        if (len(lines) > 0 and lines.count(PCIINFO_DELIMITER_BEGIN) > 0
            and lines.count(PCIINFO_DELIMITER_END)):
            begin = lines.index(PCIINFO_DELIMITER_BEGIN) + 1
            end = lines.index(PCIINFO_DELIMITER_END)
            return lines[begin : end]
    
    
    def retry_get_pci_output(get_console_output, server_id, retry=20):
        while retry > 0:
            out = get_pci_output(get_console_output, server_id)
            if out is None:
                retry = retry - 1
                time.sleep(1)
            else:
                return out
        raise Exception("Can't get the pci.info from VM!")
                                                          
    View Code

    使用cloud-init 和console-log获取硬件信息的代码的片段。

                personality = []
    
                user_data = pci.gen_user_data("
    ".join(pci.CONSOLE_DATA))
    
                server_with_pci = (self.create_test_server(
                                          wait_until='ACTIVE',
                                          adminPass=admin_pass,
                                          user_data=user_data,
                                          personality=personality,
                                          flavor=flavor_with_pci_id))
                #print self.client.get_server_metadata_item(server_with_pci['id'],"addresses")
                addresses = self.client.show_server(server_with_pci['id'])['server']
                password = 'cubswin:)'
    
                print "cirros@" + addresses["addresses"]["private"][0]["addr"]
                print password
                pci_info = pci.retry_get_pci_output(
                    self.client.get_console_output, server_with_pci["id"])
    
                # pci_info = pci.get_pci_info(disk)
                # pci_flag = linux_client.get_pci(pciid)
                expect_pci = filter(lambda x: pciid in x, pci_info)
    
                # self.assertTrue(pci_flag is not None)
                self.assertTrue(not not expect_pci)
    
                # pci_count = linux_client.get_pci_count(pciid)
                pci_count = len(expect_pci)
    
                # pci_count = pci_count.strip()
                self.assertEqual(1, pci_count)
    View Code

    使用 使用cloud-init 和 nbd获取时候,需要mount config.drive的磁盘。

    使用 file inject 和nbd获取的时候,需要开关机器。

  • 相关阅读:
    跃迁方法论 Continuous practice
    EPI online zoom session 面试算法基础知识直播分享
    台州 OJ 2648 小希的迷宫
    洛谷 P1074 靶形数独
    洛谷 P1433 DP 状态压缩
    台州 OJ FatMouse and Cheese 深搜 记忆化搜索
    台州 OJ 2676 Tree of Tree 树状 DP
    台州 OJ 2537 Charlie's Change 多重背包 二进制优化 路径记录
    台州 OJ 2378 Tug of War
    台州 OJ 2850 Key Task BFS
  • 原文地址:https://www.cnblogs.com/shaohef/p/5316104.html
Copyright © 2011-2022 走看看