VDSM Hook 例子

您必须确保不管从哪个来源安装到您的系统中的 Hook
脚本,都针对您的环境进行过全面的测试。

目标:.
此 Hook 脚本将根据 hostusb 自定义属性的值来使得虚拟机能够使用主机上的
USB 设备。如果该自定义选项的值未被设置,则不会执行任何操作。

Important

使用此 Hook
要求必须把虚拟机固定在单独一台主机上运行,该虚拟机的迁移操作都会失败。

  1. hostusb=0x[\da-fA-F]{4}:0x[\da-fA-F]{4}(&0x[\da-fA-F]{4}:0x[\da-fA-F]{4})*

上面使用的正则表达式使得 hostusb
这个自定义属性能够接受一个或者多个由“:”分隔的两个四位十六进制数(例如
0x1234:0xbeef)的组合,如果是多个的话则它们之间由“&”分隔。其中每个组合表示一个主机上的
USB 设备,前面一个四位十六进制数表示厂商的 ID,后一个十六进制数表示产品
ID(例如刚才的例子,0x1234 表示厂商,0xbeef 表示产品)。

脚本:.
/usr/libexec/vdsm/hooks/before_vm_start/50_hostusb

  1. #!/usr/bin/python
  2. import re
  3. import os
  4. import sys
  5. import grp
  6. import pwd
  7. import traceback
  8. import hooking
  9. '''
  10. host usb hook
  11. =============
  12. !!! Disclaimer !!!
  13. *******************************************
  14. The host side usb support wasn't thoroughly
  15. tests in kvm!
  16. *******************************************
  17. add hosts usb device/s to VM:
  18. <hostdev mode='subsystem' type='usb'>
  19. <source>
  20. <vendor id='0x1234'/>
  21. <product id='0xbeef'/>
  22. </source>
  23. </hostdev>
  24. syntax:
  25. hostusb=0x1234:0xbeef&0x2222:0xabaa
  26. i.e.
  27. hostusb=VendorId:ProductId (can add more then one with '&' separator)
  28. Note:
  29. The VM must be pinned to host and this hook will
  30. fail any migration attempt.
  31. '''
  32. HOOK_HOSTUSB_PATH = '/var/run/vdsm/hooks/hostusb-permissions'
  33. def log_dev_owner(devpath, user, group):
  34. entry = devpath + ":" + str(user) + ":" + str(group)
  35. if not os.path.isdir(os.path.dirname(HOOK_HOSTUSB_PATH)):
  36. os.mkdir(os.path.dirname(HOOK_HOSTUSB_PATH))
  37. if os.path.isfile(HOOK_HOSTUSB_PATH):
  38. f = file(HOOK_HOSTUSB_PATH, 'r')
  39. for line in f:
  40. if entry == line:
  41. f.close()
  42. return
  43. f = file(HOOK_HOSTUSB_PATH, 'a')
  44. f.writelines(entry)
  45. f.close()
  46. def chown(vendorid, productid):
  47. # remove the 0x from the vendor and product id
  48. devid = vendorid[2:] + ':' + productid[2:]
  49. command = ['lsusb', '-d', devid]
  50. retcode, out, err = hooking.execCmd(command, sudo=False, raw=True)
  51. if retcode != 0:
  52. sys.stderr.write('hostusb: cannot find usb device: %s\n' % devid)
  53. sys.exit(2)
  54. # find the device path:
  55. # /dev/bus/usb/xxx/xxx
  56. devpath = '/dev/bus/usb/' + out[4:7] + '/' + out[15:18]
  57. stat = os.stat(devpath)
  58. group = grp.getgrnam('qemu')
  59. gid = group.gr_gid
  60. user = pwd.getpwnam('qemu')
  61. uid = user.pw_uid
  62. # we don't use os.chown because we need sudo
  63. owner = str(uid) + ':' + str(gid)
  64. command = ['/bin/chown', owner, devpath]
  65. retcode, out, err = hooking.execCmd(command, sudo=True, raw=True)
  66. if retcode != 0:
  67. sys.stderr.write('hostusb: error chown %s to %s, err = %s\n' %
  68. (devpath, owner, err))
  69. sys.exit(2)
  70. log_dev_owner(devpath, stat.st_uid, stat.st_gid)
  71. def create_usb_device(domxml, vendorid, productid):
  72. hostdev = domxml.createElement('hostdev')
  73. hostdev.setAttribute('mode', 'subsystem')
  74. hostdev.setAttribute('type', 'usb')
  75. source = domxml.createElement('source')
  76. hostdev.appendChild(source)
  77. vendor = domxml.createElement('vendor')
  78. vendor.setAttribute('id', vendorid)
  79. source.appendChild(vendor)
  80. product = domxml.createElement('product')
  81. product.setAttribute('id', productid)
  82. source.appendChild(product)
  83. return hostdev
  84. if 'hostusb' in os.environ:
  85. try:
  86. regex = re.compile('^0x[\d,A-F,a-f]{4}$')
  87. domxml = hooking.read_domxml()
  88. devices = domxml.getElementsByTagName('devices')[0]
  89. for usb in os.environ['hostusb'].split('&'):
  90. vendorid, productid = usb.split(':')
  91. if len(regex.findall(vendorid)) != 1 or \
  92. len(regex.findall(productid)) != 1:
  93. sys.stderr.write('hostusb: bad input, expected 0x0000 format '
  94. 'for vendor and product id, input: %s:%s\n' %
  95. (vendorid, productid))
  96. sys.exit(2)
  97. hostdev = create_usb_device(domxml, vendorid, productid)
  98. devices.appendChild(hostdev)
  99. chown(vendorid, productid)
  100. hooking.write_domxml(domxml)
  101. except:
  102. sys.stderr.write('hostusb: [unexpected error]: %s\n' %
  103. traceback.format_exc())
  104. sys.exit(2)