[Azure]通過waagent代碼找到臨時磁盤的設備名

Azure的Linux虛擬機默認會有一個臨時磁盤,正常情況下設備名是/dev/sdb,但是由於設備識別順序是隨機的,所以重啓的時候,臨時磁盤的設備名可能未必是/dev/sdb,那麼waagent是如何將/dev/sdb掛在到/mnt/resource下的呢?

waagent相關代碼都在/usr/lib/python2.7/site-packages/azurelinuxagent目錄下(具體分析過程這裏不再贅述)。

我們進入resourcedisk子目錄,找到default.py文件,看一下activate_resource_disk方法,我們看到通過調用mount_resource_disk方法進行臨時磁盤的掛載:
def activate_resource_disk(self):
    logger.info("Activate resource disk")
    try:
        mount_point = conf.get_resourcedisk_mountpoint()
        mount_point = self.mount_resource_disk(mount_point)
        warning_file = os.path.join(mount_point,
                                    DATALOSS_WARNING_FILE_NAME)
        try:
            fileutil.write_file(warning_file, DATA_LOSS_WARNING)
        except IOError as e:
            logger.warn("Failed to write data loss warning:{0}", e)
        return mount_point
    except ResourceDiskError as e:
        logger.error("Failed to mount resource disk {0}", e)
        add_event(name=AGENT_NAME, is_success=False, message=ustr(e),
                  op=WALAEventOperation.ActivateResourceDisk)

我們繼續在這個文件中查看mount_resource_disk方法,可以看到是在device_for_ide_port這個方法中得到設備名的:
def mount_resource_disk(self, mount_point):
    device = self.osutil.device_for_ide_port(1)
    if device is None:
        raise ResourceDiskError("unable to detect disk topology")


    device = "/dev/{0}".format(device)
    partition = device + "1"
    mount_list = shellutil.run_get_output("mount")[1]
    existing = self.osutil.get_mount_point(mount_list, device)

    if existing:
        logger.info("Resource disk [{0}] is already mounted [{1}]",
                    partition,
                    existing)
        return existing

在文件開頭引用了osutil命名空間中的方法:
from azurelinuxagent.common.osutil import get_osutil

並且在構造函數中制定了self.osutil屬性:
def __init__(self):
    self.osutil = get_osutil()
    self.fs = conf.get_resourcedisk_filesystem()

接着我們到/usr/lib/python2.7/site-packages/azurelinuxagent/common/osutil中查看對應的源代碼default.py文件,找到device_for_ide_port這個方法:
def device_for_ide_port(self, port_id):
    """
    Return device name attached to ide port 'n'.
    """
    if port_id > 3:
        return None
    g0 = "00000000"
    if port_id > 1:
        g0 = "00000001"
        port_id = port_id - 2
    device = None
    path = "/sys/bus/vmbus/devices/"
    if os.path.exists(path):
        for vmbus in os.listdir(path):
            deviceid = fileutil.read_file(os.path.join(path, vmbus, "device_id"))
            guid = deviceid.lstrip('{').split('-')
            if guid[0] == g0 and guid[1] == "000" + ustr(port_id):
                for root, dirs, files in os.walk(path + vmbus):
                    if root.endswith("/block"):
                        device = dirs[0]
                        break
                    else : #older distros
                        for d in dirs:
                            if ':' in d and "block" == d.split(':')[0]:
                                device = d.split(':')[1]
                                break
                break
    return device

看起來比較亂,我們看到邏輯中是找到guid以00000000開頭的,並且guid第二部分是0001(注意前面參數裏面port_id寫的是1,所以根據guid[1] == "000" + ustr(port_id)判斷條件是0001)的一個blockId,我們看一下/sys/bus/vmbus/devices/下面符合條件的blockId:

定位到是這個ID:

00000000-0001-8899-0000-000000000000

根據這個,我們將device_for_ide_port方法簡化成下下面的腳本在這臺機器上跑一下:

import os
path = "/sys/bus/vmbus/devices/"
vmbus = "00000000-0001-8899-0000-000000000000"
for root, dirs, files in os.walk(path + vmbus):
    if root.endswith("/block"):
        root
        dirs
        break

跑完得到結果:

可以看到,是從/sys/bus/vmbus/devices/00000000-0001-8899-0000-000000000000/host5/target5:0:1/5:0:1:0/block這個目錄下讀到了sdb這個目錄,這個目錄就是臨時磁盤的設備名。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章