diff options
author | Cole Robinson <crobinso@redhat.com> | 2020-11-11 15:13:35 -0500 |
---|---|---|
committer | Cole Robinson <crobinso@redhat.com> | 2020-11-11 18:07:50 -0500 |
commit | c4f5812290beace541dca9668f373bc35e1e8136 (patch) | |
tree | f6f21eaa0a2e1046ffaa601f6ef4595f070de56b | |
parent | b3ff59c75ca5958fae861d13c92bcbb0e025ec66 (diff) | |
download | virt-manager-c4f5812290beace541dca9668f373bc35e1e8136.tar.gz |
device: disk: Group related functions
Signed-off-by: Cole Robinson <crobinso@redhat.com>
-rw-r--r-- | virtinst/devices/disk.py | 438 |
1 files changed, 225 insertions, 213 deletions
diff --git a/virtinst/devices/disk.py b/virtinst/devices/disk.py index 134d5547..6841f425 100644 --- a/virtinst/devices/disk.py +++ b/virtinst/devices/disk.py @@ -444,10 +444,178 @@ class DeviceDisk(Device): self.conn, self._get_xmlpath(), self._xmltype, self.driver_type) + ################## + # XML properties # + ################## + + _xmltype = XMLProperty("./@type") + _device = XMLProperty("./@device") + + driver_name = XMLProperty("./driver/@name") + driver_type = XMLProperty("./driver/@type") + + source = XMLChildProperty(_DiskSource, is_single=True) + + auth_username = XMLProperty("./auth/@username") + auth_secret_type = XMLProperty("./auth/secret/@type") + auth_secret_uuid = XMLProperty("./auth/secret/@uuid") + + snapshot_policy = XMLProperty("./@snapshot") + + driver_copy_on_read = XMLProperty("./driver/@copy_on_read", is_onoff=True) + + sgio = XMLProperty("./@sgio") + rawio = XMLProperty("./@rawio") + + bus = XMLProperty("./target/@bus") + target = XMLProperty("./target/@dev") + removable = XMLProperty("./target/@removable", is_onoff=True) + + read_only = XMLProperty("./readonly", is_bool=True) + shareable = XMLProperty("./shareable", is_bool=True) + driver_cache = XMLProperty("./driver/@cache") + driver_discard = XMLProperty("./driver/@discard") + driver_detect_zeroes = XMLProperty("./driver/@detect_zeroes") + driver_io = XMLProperty("./driver/@io") + driver_iothread = XMLProperty("./driver/@iothread", is_int=True) + + error_policy = XMLProperty("./driver/@error_policy") + serial = XMLProperty("./serial") + wwn = XMLProperty("./wwn") + startup_policy = XMLProperty("./source/@startupPolicy") + logical_block_size = XMLProperty("./blockio/@logical_block_size") + physical_block_size = XMLProperty("./blockio/@physical_block_size") + + iotune_rbs = XMLProperty("./iotune/read_bytes_sec", is_int=True) + iotune_ris = XMLProperty("./iotune/read_iops_sec", is_int=True) + iotune_tbs = XMLProperty("./iotune/total_bytes_sec", is_int=True) + iotune_tis = XMLProperty("./iotune/total_iops_sec", is_int=True) + iotune_wbs = XMLProperty("./iotune/write_bytes_sec", is_int=True) + iotune_wis = XMLProperty("./iotune/write_iops_sec", is_int=True) + + seclabels = XMLChildProperty(DeviceSeclabel, relative_xpath="./source") + + geometry_cyls = XMLProperty("./geometry/@cyls", is_int=True) + geometry_heads = XMLProperty("./geometry/@heads", is_int=True) + geometry_secs = XMLProperty("./geometry/@secs", is_int=True) + geometry_trans = XMLProperty("./geometry/@trans") + + reservations_managed = XMLProperty("./source/reservations/@managed") + reservations_source_type = XMLProperty("./source/reservations/source/@type") + reservations_source_path = XMLProperty("./source/reservations/source/@path") + reservations_source_mode = XMLProperty("./source/reservations/source/@mode") + + ############################# - # Public property-esque API # + # Internal defaults helpers # ############################# + def _get_default_type(self): + if self.source.pool or self.source.volume: + return DeviceDisk.TYPE_VOLUME + if not self._storage_backend.is_stub(): + return self._storage_backend.get_dev_type() + if self.source.protocol: + return DeviceDisk.TYPE_NETWORK + return self.TYPE_FILE + + def _get_default_driver_name(self): + if not self.path: + return None + + # Recommended xen defaults from here: + # https://bugzilla.redhat.com/show_bug.cgi?id=1171550#c9 + # If type block, use name=phy. Otherwise do the same as qemu + if self.conn.is_xen() and self.type == self.TYPE_BLOCK: + return self.DRIVER_NAME_PHY + if self.conn.support.conn_disk_driver_name_qemu(): + return self.DRIVER_NAME_QEMU + return None + + def _get_default_driver_type(self): + """ + Set driver type from passed parameters + + Where possible, we want to force /driver/@type = "raw" if installing + a QEMU VM. Without telling QEMU to expect a raw file, the emulator + is forced to autodetect, which has security implications: + + https://lists.gnu.org/archive/html/qemu-devel/2008-04/msg00675.html + """ + if self.driver_name != self.DRIVER_NAME_QEMU: + return None + + drvtype = self._storage_backend.get_driver_type() + return _qemu_sanitize_drvtype(self.type, drvtype) + + def _get_type(self): + if self._xmltype: + return self._xmltype + return self._get_default_type() + def _set_type(self, val): + self._xmltype = val + type = property(_get_type, _set_type) + + def _get_device(self): + if self._device: + return self._device + return self.DEVICE_DISK + def _set_device(self, val): + self._device = val + device = property(_get_device, _set_device) + + + ############################ + # Storage backend handling # + ############################ + + def _change_backend(self, path, vol_object, parent_pool): + backend = diskbackend.StorageBackend(self.conn, path, + vol_object, parent_pool) + self._storage_backend = backend + + def set_backend_for_existing_path(self): + # This is an entry point for parsexml Disk instances to request + # a _storage_backend to be initialized from the XML path. That + # will cause validate() to actually validate the path exists. + # We need this so addhw XML editing will still validate the disk path + if self._storage_backend.is_stub(): + self._resolve_storage_backend() + + def _resolve_storage_backend(self): + """ + Convert the relevant <source> XML values into self._storage_backend + """ + path = None + vol_object = None + parent_pool = None + self._source_volume_err = None + typ = self._get_default_type() + + if self.type == DeviceDisk.TYPE_NETWORK: + # Fill in a completed URL for virt-manager UI, path comparison, etc + path = self.source.build_url_from_network() + + if typ == DeviceDisk.TYPE_VOLUME: + try: + parent_pool = self.conn.storagePoolLookupByName( + self.source.pool) + vol_object = parent_pool.storageVolLookupByName( + self.source.volume) + except Exception as e: + self._source_volume_err = str(e) + log.debug("Error fetching source pool=%s vol=%s", + self.source.pool, self.source.volume, exc_info=True) + + if vol_object is None and path is None: + path = self._get_xmlpath() + + if path and not vol_object and not parent_pool: + (vol_object, parent_pool) = diskbackend.manage_path( + self.conn, path) + + self._change_backend(path, vol_object, parent_pool) + def _get_path(self): if (self._storage_backend.is_stub() and not self._storage_backend.get_path()): @@ -467,14 +635,6 @@ class DeviceDisk(Device): self._set_xmlpath(self.path) path = property(_get_path, _set_path) - def set_backend_for_existing_path(self): - # This is an entry point for parsexml Disk instances to request - # a _storage_backend to be initialized from the XML path. That - # will cause validate() to actually validate the path exists. - # We need this so addhw XML editing will still validate the disk path - if self._storage_backend.is_stub(): - self._resolve_storage_backend() - def set_vol_object(self, vol_object, parent_pool): log.debug("disk.set_vol_object: volxml=\n%s", vol_object.XMLDesc(0)) @@ -500,46 +660,6 @@ class DeviceDisk(Device): return self._storage_backend.get_size() - ############################# - # Internal defaults helpers # - ############################# - - def _get_default_driver_name(self): - if not self.path: - return None - - # Recommended xen defaults from here: - # https://bugzilla.redhat.com/show_bug.cgi?id=1171550#c9 - # If type block, use name=phy. Otherwise do the same as qemu - if self.conn.is_xen() and self.type == self.TYPE_BLOCK: - return self.DRIVER_NAME_PHY - if self.conn.support.conn_disk_driver_name_qemu(): - return self.DRIVER_NAME_QEMU - return None - - def _get_default_driver_type(self): - """ - Set driver type from passed parameters - - Where possible, we want to force /driver/@type = "raw" if installing - a QEMU VM. Without telling QEMU to expect a raw file, the emulator - is forced to autodetect, which has security implications: - - https://lists.gnu.org/archive/html/qemu-devel/2008-04/msg00675.html - """ - if self.driver_name != self.DRIVER_NAME_QEMU: - return None - - drvtype = self._storage_backend.get_driver_type() - return _qemu_sanitize_drvtype(self.type, drvtype) - - - ############################# - # XML source media handling # - ############################# - - source = XMLChildProperty(_DiskSource, is_single=True) - def _set_source_network_from_storage(self, volxml, poolxml): self.type = "network" if poolxml.auth_type: @@ -558,16 +678,6 @@ class DeviceDisk(Device): elif self._storage_backend.get_path(): self.source.set_from_url(self._storage_backend.get_path()) - def _get_default_type(self): - if self.source.pool or self.source.volume: - return DeviceDisk.TYPE_VOLUME - if not self._storage_backend.is_stub(): - return self._storage_backend.get_dev_type() - if self.source.protocol: - return DeviceDisk.TYPE_NETWORK - return self.TYPE_FILE - - def _disk_type_to_object_prop_name(self): disk_type = self.type if disk_type == DeviceDisk.TYPE_BLOCK: @@ -590,6 +700,7 @@ class DeviceDisk(Device): if self.source.dir: return self.source.dir return None + def _set_xmlpath(self, val): self.source.clear_source() @@ -602,118 +713,6 @@ class DeviceDisk(Device): return return setattr(self.source, propname, val) - - ################## - # XML properties # - ################## - - # type, device, driver_name, driver_type handling - # These are all weirdly intertwined so require some special handling - def _get_type(self): - if self._xmltype: - return self._xmltype - return self._get_default_type() - def _set_type(self, val): - self._xmltype = val - type = property(_get_type, _set_type) - _xmltype = XMLProperty("./@type") - - def _get_device(self): - if self._device: - return self._device - return self.DEVICE_DISK - def _set_device(self, val): - self._device = val - device = property(_get_device, _set_device) - _device = XMLProperty("./@device") - driver_name = XMLProperty("./driver/@name") - driver_type = XMLProperty("./driver/@type") - - auth_username = XMLProperty("./auth/@username") - auth_secret_type = XMLProperty("./auth/secret/@type") - auth_secret_uuid = XMLProperty("./auth/secret/@uuid") - - snapshot_policy = XMLProperty("./@snapshot") - - driver_copy_on_read = XMLProperty("./driver/@copy_on_read", is_onoff=True) - - sgio = XMLProperty("./@sgio") - rawio = XMLProperty("./@rawio") - - bus = XMLProperty("./target/@bus") - target = XMLProperty("./target/@dev") - removable = XMLProperty("./target/@removable", is_onoff=True) - - read_only = XMLProperty("./readonly", is_bool=True) - shareable = XMLProperty("./shareable", is_bool=True) - driver_cache = XMLProperty("./driver/@cache") - driver_discard = XMLProperty("./driver/@discard") - driver_detect_zeroes = XMLProperty("./driver/@detect_zeroes") - driver_io = XMLProperty("./driver/@io") - driver_iothread = XMLProperty("./driver/@iothread", is_int=True) - - error_policy = XMLProperty("./driver/@error_policy") - serial = XMLProperty("./serial") - wwn = XMLProperty("./wwn") - startup_policy = XMLProperty("./source/@startupPolicy") - logical_block_size = XMLProperty("./blockio/@logical_block_size") - physical_block_size = XMLProperty("./blockio/@physical_block_size") - - iotune_rbs = XMLProperty("./iotune/read_bytes_sec", is_int=True) - iotune_ris = XMLProperty("./iotune/read_iops_sec", is_int=True) - iotune_tbs = XMLProperty("./iotune/total_bytes_sec", is_int=True) - iotune_tis = XMLProperty("./iotune/total_iops_sec", is_int=True) - iotune_wbs = XMLProperty("./iotune/write_bytes_sec", is_int=True) - iotune_wis = XMLProperty("./iotune/write_iops_sec", is_int=True) - - seclabels = XMLChildProperty(DeviceSeclabel, relative_xpath="./source") - - geometry_cyls = XMLProperty("./geometry/@cyls", is_int=True) - geometry_heads = XMLProperty("./geometry/@heads", is_int=True) - geometry_secs = XMLProperty("./geometry/@secs", is_int=True) - geometry_trans = XMLProperty("./geometry/@trans") - - reservations_managed = XMLProperty("./source/reservations/@managed") - reservations_source_type = XMLProperty("./source/reservations/source/@type") - reservations_source_path = XMLProperty("./source/reservations/source/@path") - reservations_source_mode = XMLProperty("./source/reservations/source/@mode") - - - ################################# - # Validation assistance methods # - ################################# - - def _resolve_storage_backend(self): - path = None - vol_object = None - parent_pool = None - self._source_volume_err = None - typ = self._get_default_type() - - if self.type == DeviceDisk.TYPE_NETWORK: - # Fill in a completed URL for virt-manager UI, path comparison, etc - path = self.source.build_url_from_network() - - if typ == DeviceDisk.TYPE_VOLUME: - try: - parent_pool = self.conn.storagePoolLookupByName( - self.source.pool) - vol_object = parent_pool.storageVolLookupByName( - self.source.volume) - except Exception as e: - self._source_volume_err = str(e) - log.debug("Error fetching source pool=%s vol=%s", - self.source.pool, self.source.volume, exc_info=True) - - if vol_object is None and path is None: - path = self._get_xmlpath() - - if path and not vol_object and not parent_pool: - (vol_object, parent_pool) = diskbackend.manage_path( - self.conn, path) - - self._change_backend(path, vol_object, parent_pool) - def set_local_disk_to_clone(self, disk, sparse): """ Set a path to manually clone (as in, not through libvirt) @@ -721,6 +720,11 @@ class DeviceDisk(Device): self._storage_backend = diskbackend.CloneStorageCreator(self.conn, self.path, disk.path, disk.get_size(), sparse) + + ##################### + # Utility functions # + ##################### + def is_cdrom(self): return self.device == self.DEVICE_CDROM def is_floppy(self): @@ -736,27 +740,6 @@ class DeviceDisk(Device): # Don't error for unknown types return True - def _change_backend(self, path, vol_object, parent_pool): - backend = diskbackend.StorageBackend(self.conn, path, - vol_object, parent_pool) - self._storage_backend = backend - - def sync_path_props(self): - """ - Fills in the values of type, driver_type, and driver_name for - the associated backing storage. This needs to be manually called - if changing an existing disk's media. - """ - path = self._get_xmlpath() - - self.type = self._get_default_type() - self.driver_name = self._get_default_driver_name() - self.driver_type = self._get_default_driver_type() - - # Need to retrigger this if self.type changed - if path: - self._set_xmlpath(path) - def wants_storage_creation(self): """ If true, this disk needs storage creation parameters or things @@ -764,24 +747,10 @@ class DeviceDisk(Device): """ return not self._storage_backend.exists() - def validate(self): - if self.path is None: - if self._source_volume_err: - raise RuntimeError(self._source_volume_err) - - if not self.can_be_empty(): - raise ValueError(_("Device type '%s' requires a path") % - self.device) - - return - if (not self._storage_backend.exists() and - not self._storage_backend.will_create_storage()): - raise ValueError( - _("Must specify storage creation parameters for " - "non-existent path '%s'.") % self.path) - - self._storage_backend.validate() + #################### + # Storage building # + #################### def build_storage(self, meter): """ @@ -803,6 +772,30 @@ class DeviceDisk(Device): parent_pool = self.get_vol_install().pool self._change_backend(None, vol_object, parent_pool) + + ###################### + # validation helpers # + ###################### + + def validate(self): + if self.path is None: + if self._source_volume_err: + raise RuntimeError(self._source_volume_err) + + if not self.can_be_empty(): + raise ValueError(_("Device type '%s' requires a path") % + self.device) + + return + + if (not self._storage_backend.exists() and + not self._storage_backend.will_create_storage()): + raise ValueError( + _("Must specify storage creation parameters for " + "non-existent path '%s'.") % self.path) + + self._storage_backend.validate() + def is_size_conflict(self): """ reports if disk size conflicts with available space @@ -828,6 +821,26 @@ class DeviceDisk(Device): return ret + ########################### + # Misc functional helpers # + ########################### + + def sync_path_props(self): + """ + Fills in the values of type, driver_type, and driver_name for + the associated backing storage. This needs to be manually called + if changing an existing disk's media. + """ + path = self._get_xmlpath() + + self.type = self._get_default_type() + self.driver_name = self._get_default_driver_name() + self.driver_type = self._get_default_driver_type() + + # Need to retrigger this if self.type changed + if path: + self._set_xmlpath(path) + def get_target_prefix(self): """ Returns the suggested disk target prefix (hd, xvd, sd ...) for the @@ -857,7 +870,6 @@ class DeviceDisk(Device): # sata, scsi, usb, sd return _return("sd") - def generate_target(self, skip_targets): """ Generate target device ('hda', 'sdb', etc..) for disk, excluding @@ -922,9 +934,9 @@ class DeviceDisk(Device): self.generate_target(used) - ################## - # Default config # - ################## + ######################### + # set_defaults handling # + ######################### def _default_bus(self, guest): if self.is_floppy(): |