[virt-tools-list] [PATCH v2] domain: add 'pre-startup' signal and do nodedevs checking

Cole Robinson crobinso at redhat.com
Sat May 11 15:49:44 UTC 2013


On 05/11/2013 11:33 AM, Cole Robinson wrote:
> On 05/10/2013 05:49 AM, Guannan Ren wrote:
>> This patch introduces 'pre-start' signal and registers
>> nodedev checking handler to check duplicate USB devices.
>> If virt-manager can not identify unique usb device any more
>> before domain startup, it will throw a tip error to tell it
>> is time to reattach host USB devices to get updated bus/addr info.
>> ---
>>  virtManager/domain.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++++++
>>  1 file changed, 60 insertions(+)
>>
>> diff --git a/virtManager/domain.py b/virtManager/domain.py
>> index 791f2af..26cff37 100644
>> --- a/virtManager/domain.py
>> +++ b/virtManager/domain.py
>> @@ -149,6 +149,7 @@ class vmmDomain(vmmLibvirtObject):
>>          "status-changed": (GObject.SignalFlags.RUN_FIRST, None, [int, int]),
>>          "resources-sampled": (GObject.SignalFlags.RUN_FIRST, None, []),
>>          "inspection-changed": (GObject.SignalFlags.RUN_FIRST, None, []),
>> +        "pre-startup": (GObject.SignalFlags.RUN_FIRST, None, [])
>>      }
>>  
>>      def __init__(self, conn, backend, uuid):
>> @@ -194,6 +195,9 @@ class vmmDomain(vmmLibvirtObject):
>>          self._stats_disk_supported = True
>>          self._stats_disk_skip = []
>>  
>> +        # pre_startup global flags
>> +        self._prestartup_hostdev_check_failed = False
>> +
>>          self.inspection = vmmInspectionData()
>>  
>>          if isinstance(self._backend, virtinst.Guest):
>> @@ -252,7 +256,59 @@ class vmmDomain(vmmLibvirtObject):
>>  
>>          self.connect("status-changed", self._update_start_vcpus)
>>          self.connect("config-changed", self._reparse_xml)
>> +        self.connect("pre-startup", self._prestartup_nodedev_check)
>> +
>> +    #####################
>> +    # checking routines #
>> +    #####################
>> +
>> +    def attrVal(self, attr):
>> +        if hasattr(self, attr):
>> +            return getattr(self, attr)
>> +        return False
>> +
>> +    # class closure to initialize global variable.
>> +    def do_pre_startup(self):
>> +        if getattr(self, "_prestartup_hostdev_check_failed"):
>> +            self._prestartup_hostdev_check_failed = False
>> +            # Initialize falure reasons
>> +            self._hostdev_non_exist = False
>> +            self._hostdev_multiples = False
>>  
>> +    def _prestartup_nodedev_check(self, data=None):
>> +        for hostdev in self.get_hostdev_devices():
>> +            devtype = hostdev.type
>> +
>> +            if devtype != "usb":
>> +                continue
>> +
>> +            vendor = hostdev.vendor
>> +            product = hostdev.product
>> +            bus = hostdev.bus
>> +            device = hostdev.device
>> +
>> +            if vendor and product:
>> +                count = self.conn.get_nodedevs_number("usb_device",
>> +                                                      vendor,
>> +                                                      product)
>> +                if not count:
>> +                    self._prestartup_hostdev_check_failed = True
>> +                    self._hostdev_non_exist = True
>> +
>> +                elif count > 1 and not (bus and device):
>> +                    self._prestartup_hostdev_check_failed = True
>> +                    self._hostdev_multiples = True
>> +
>> +    def _prestartup_nodedev_report(self):
>> +        if self._prestartup_hostdev_check_failed:
>> +            if self.attrVal("_hostdev_non_exist"):
>> +                raise RuntimeError(_("Could not find any USB device"))
>> +
> 
> I would drop this error and just let libvirt/qemu handle it for us.
> 
>> +            elif self.attrVal("_hostdev_multiples"):
>> +                raise RuntimeError(_("The attached USB device "
>> +                                     "is not unique, please remove "
>> +                                     "and add it again!"))
> 
> I'd change this message to:
> 
> There is more than one '%(prettyname)s' device attached to your host, and we
> can't determine which one to use for your guest.
> 
> To fix this, remove and reattach the USB device to your guest using the 'Add
> Hardware' wizard.
> 
>> +        return;
>>  
>>      ###########################
>>      # Misc API getter methods #
>> @@ -1171,6 +1227,10 @@ class vmmDomain(vmmLibvirtObject):
>>          if self.get_cloning():
>>              raise RuntimeError(_("Cannot start guest while cloning "
>>                                   "operation in progress"))
>> +
>> +        self.emit("pre-startup")
>> +        self._prestartup_nodedev_report()
>> +
>>          self._backend.create()
>>          self.idle_add(self.force_update_status)
>>  
>>
> 
> Hmm, that return value mangling is sub-optimal, but indeed I can't get emit to
> return values like I thought it could.
> 
> But I remembered a trick we use elsewhere in virt-manager already. If you pass
> a list as a signal argument, the signal handler can add values to it, which
> the emitter can than access. You can then just have the signal callback return
> the string error directly.
> 
> Here's an example to show how it works:
> 
> 
> diff --git a/virtManager/domain.py b/virtManager/domain.py
> index 7c3f952..f2a9041 100644
> --- a/virtManager/domain.py
> +++ b/virtManager/domain.py
> @@ -149,7 +149,7 @@ class vmmDomain(vmmLibvirtObject):
>          "status-changed": (GObject.SignalFlags.RUN_FIRST, None, [int, int]),
>          "resources-sampled": (GObject.SignalFlags.RUN_FIRST, None, []),
>          "inspection-changed": (GObject.SignalFlags.RUN_FIRST, None, []),
> -        "pre-startup": (GObject.SignalFlags.RUN_FIRST, None, [])
> +        "pre-startup": (GObject.SignalFlags.RUN_FIRST, None, [object])
>      }
> 
>      def __init__(self, conn, backend, uuid):
> @@ -275,7 +275,10 @@ class vmmDomain(vmmLibvirtObject):
>              self._hostdev_non_exist = False
>              self._hostdev_multiples = False
> 
> -    def _prestartup_nodedev_check(self, data=None):
> +    def _prestartup_nodedev_check(self, src, ret):
> +        print "in hook ret", ret
> +        ret.append("frobber")
> +        return
>          for hostdev in self.get_hostdev_devices():
>              devtype = hostdev.type
> 
> @@ -1228,7 +1231,9 @@ class vmmDomain(vmmLibvirtObject):
>              raise RuntimeError(_("Cannot start guest while cloning "
>                                   "operation in progress"))
> 
> -        self.emit("pre-startup")
> +        ret = []
> +        self.emit("pre-startup", ret)
> +        print "emit ret", ret
>          self._prestartup_nodedev_report()
> 
>          self._backend.create()
> 

Also I just pushed a commit to tests/testdriver.xml to add duplicate devices,
and a guest named test-duplicate-usb so you can this logic without having to
interact with real guests/hardware.

- Cole




More information about the virt-tools-list mailing list