1

我正在尝试为一些开源软件编写补丁,因为它并不能完全满足我的要求——除了我根本不懂 Python!我希望这很简单,但它打败了我。

背景:我正在编写的补丁是针对我用来管理 KVM 虚拟机集群的 Ganeti,但它不支持 KVM 和 Qemu 的所有可能的命令行选项,例如 USB 直通,所以我正在尝试修改它以允许这样做。

kvm_cmd.extend()用于添加在启动 VM 时将传递的 KVM CLI 参数数组。如果参数是空格分隔的,每个参数都变成一个单独的字符串,例如-usb -device usb-host,hostbus=1,hostdev=14变成"-usb", "-device", "usb-host,hostbus=1,hostdev=14".

编译代码后我正在运行以下命令:

gnt-instance modify -H usb_pass="1;14"

我希望将其添加到现有的命令行参数列表中"-usb -device usb-host,hostbus=1,hostdev=14"。这是我添加的代码(以及在其他地方声明变量;HV_USBPASSTHROUGH是一个字符串,但这是魔法发生的地方)

usb_pass = instance.hvparams[constants.HV_USBPASSTHROUGH]
if usb_pass:
    usb_pass_arr = []
    usb_pass_arr = usb_pass.split(";")
    kvm_cmd.extend(["-usb", "-device", "usb-host,hostbus=%s,hostaddr=%s" %
                    usb_pass_arr])

使用上述代码运行上述命令时出现以下错误: Could not start instance: Error while executing backend function: not enough arguments for format string

4

7 回答 7

7

你有两个`%s"usb-host,hostbus=%s,hostaddr=%s"但只提供一个参数,一个列表,其中需要一个元组。

采用

"usb-host,hostbus=%s,hostaddr=%s" % tuple(usb_pass_arr)

tuple()内置将可迭代对象转换为元组。

于 2012-10-04T11:18:39.893 回答
3

改变

"usb-host,hostbus=%s,hostaddr=%s" % usb_pass_arr

"usb-host,hostbus=%s,hostaddr=%s" % tuple(usb_pass_arr)

usb_pass_arr也不需要预初始化,因为split()返回一个新列表。

于 2012-10-04T11:22:56.970 回答
3

您已经得到了“旧”样式格式的答案;使用新样式格式.format()您可以使用可变长度参数语法执行以下操作,以自动解压缩usb_pass到函数参数中format()

'usb-host,hostbus={},hostaddr={}'.format(*usb_pass)
于 2012-10-04T11:49:40.173 回答
1

您需要做的就是usb_pass_arr作为元组传递,这是字符串格式化所期望的。

usb_pass = instance.hvparams[constants.HV_USBPASSTHROUGH]
if usb_pass:
    usb_pass_arr = [] #you can remove this line
    usb_pass_arr = tuple(usb_pass.split(";")) #a tuple is an immutable list
    kvm_cmd.extend(["-usb", "-device", "usb-host,hostbus=%s,hostaddr=%s" %
                    usb_pass_arr])
于 2012-10-04T11:25:15.813 回答
1

正如人们已经写过的那样,您需要使用 . 将列表转换为元组tuple(usb_pass_arr)。请参阅python 文档中的段落:

如果格式需要单个参数,则值可以是单个非元组对象。否则,值必须是具有格式字符串指定的项目数的元组,或者是单个映射对象(例如,字典)。

于 2012-10-04T11:27:11.070 回答
0

粗略的猜测——你需要改用这个:

"usb-host,hostbus=%s,hostaddr=%s" % (usb_pass_arr[0], usb_pass_arr[1])
于 2012-10-04T11:24:08.030 回答
0

嗨,David Morton 和其他任何感兴趣的人,这是针对每个实例单个 USB 设备的 Ganeti 2.6.0 USB 直通;

    diff -r -c ganeti-2.6.0_original/lib/constants.py ganeti-2.6.0_changed/lib/constants.py
*** ganeti-2.6.0_original/lib/constants.py  2012-07-27 12:31:48.000000000 +0100
--- ganeti-2.6.0_changed/lib/constants.py   2012-10-04 13:46:15.881572099 +0100
***************
*** 770,775 ****
--- 770,776 ----
  HV_KVM_USE_CHROOT = "use_chroot"
  HV_CPU_MASK = "cpu_mask"
  HV_MEM_PATH = "mem_path"
+ HV_USBPASSTHROUGH = "usb_pass"
  HV_BLOCKDEV_PREFIX = "blockdev_prefix"
  HV_REBOOT_BEHAVIOR = "reboot_behavior"

***************
*** 824,829 ****
--- 825,831 ----
    HV_KVM_USE_CHROOT: VTYPE_BOOL,
    HV_CPU_MASK: VTYPE_STRING,
    HV_MEM_PATH: VTYPE_STRING,
+   HV_USBPASSTHROUGH: VTYPE_STRING,
    HV_BLOCKDEV_PREFIX: VTYPE_STRING,
    HV_REBOOT_BEHAVIOR: VTYPE_STRING,
    }
***************
*** 1809,1814 ****
--- 1811,1817 ----
      HV_MEM_PATH: "",
      HV_REBOOT_BEHAVIOR: INSTANCE_REBOOT_ALLOWED,
      HV_CPU_MASK: CPU_PINNING_ALL,
+     HV_USBPASSTHROUGH: "",
      },
    HT_FAKE: {
      },
Only in ganeti-2.6.0_changed/lib/: .dir
Only in ganeti-2.6.0_changed/lib/: _generated_rpc.py
Only in ganeti-2.6.0_changed/lib/http: .dir
Only in ganeti-2.6.0_changed/lib/hypervisor: .dir
diff -r -c ganeti-2.6.0_original/lib/hypervisor/hv_kvm.py ganeti-2.6.0_changed/lib/hypervisor/hv_kvm.py
*** ganeti-2.6.0_original/lib/hypervisor/hv_kvm.py  2012-07-27 13:27:41.000000000 +0100
--- ganeti-2.6.0_changed/lib/hypervisor/hv_kvm.py   2012-10-04 13:46:54.993572107 +0100
***************
*** 490,495 ****
--- 490,496 ----
      constants.HV_VHOST_NET: hv_base.NO_CHECK,
      constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK,
      constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK,
+     constants.HV_USBPASSTHROUGH:  hv_base.NO_CHECK,
      constants.HV_REBOOT_BEHAVIOR:
        hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS),
      constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK,
***************
*** 1257,1262 ****
--- 1258,1268 ----
      kvm_nics = instance.nics
      hvparams = hvp

+     usb_pass = instance.hvparams[constants.HV_USBPASSTHROUGH]
+     if usb_pass:
+         usb_pass_arr = usb_pass.split(";")
+         kvm_cmd.extend(["-usb", "-device", "usb-host,hostbus=%s,hostaddr=%s" % tuple(usb_pass_arr)])
+ 
      return (kvm_cmd, kvm_nics, hvparams)

    def _WriteKVMRuntime(self, instance_name, data):
Only in ganeti-2.6.0_changed/lib/impexpd: .dir
Only in ganeti-2.6.0_changed/lib/masterd: .dir
diff -r -c ganeti-2.6.0_original/lib/query.py ganeti-2.6.0_changed/lib/query.py
*** ganeti-2.6.0_original/lib/query.py  2012-07-27 12:31:48.000000000 +0100
--- ganeti-2.6.0_changed/lib/query.py   2012-10-04 13:46:26.625572103 +0100
***************
*** 1745,1750 ****
--- 1745,1751 ----
      constants.HV_NIC_TYPE: "NIC_type",
      constants.HV_PAE: "PAE",
      constants.HV_VNC_BIND_ADDRESS: "VNC_bind_address",
+     constants.HV_USBPASSTHROUGH: "usb_pass",
      }

    fields = [
Only in ganeti-2.6.0_changed/lib/rapi: .dir
Only in ganeti-2.6.0_changed/lib/server: .dir
Only in ganeti-2.6.0_changed/lib/tools: .dir
Only in ganeti-2.6.0_changed/lib/utils: .dir
Only in ganeti-2.6.0_changed/lib/: _vcsversion.py
Only in ganeti-2.6.0_changed/lib/watcher: .dir
于 2012-10-04T12:48:37.797 回答