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 ospath = "/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這個目錄,這個目錄就是臨時磁盤的設備名。