createvol: Drop Allocation field in favor of checkbox

Inspired by some discussion from here:
https://bugzilla.redhat.com/show_bug.cgi?id=1759454

Most libvirt storage volume creation doesn't actually do anything
with allocation, besides interpreting cap == alloc and cap != alloc.
The exceptions are zfs volumes, and raw file volumes. But it's unclear
what the usecase is for the latter at all.

This drops the allocation spinner and adds checkbox in its place
'Allocate entire volume now'. When enabled, it sets cap == alloc.

We only show this for file volumes. For qcow2 it defaults to unselected
(sparse), for all others it defaults to selected. If it's not showing,
it defaults to selected.

Bundled with this change is showing this field for qcow2, where
we previously only allowed nonsparse here. Libvirt and qemu-img
support non-sparse qcow2 these days.

Signed-off-by: Cole Robinson <crobinso@redhat.com>
This commit is contained in:
Cole Robinson 2020-09-20 16:44:52 -04:00
parent 5c1f4b2386
commit 2f7931da63
3 changed files with 59 additions and 118 deletions

View File

@ -28,15 +28,15 @@ def testCreateVolDefault(app):
name = win.find("Name:", "text")
# Create a default qcow2 volume
lib.utils.check(lambda: name.text == "vol")
newname = "a-newvol"
name.set_text(newname)
win.find("Max Capacity:", "spin button").set_text("10.5")
newname = "vol"
lib.utils.check(lambda: name.text == newname)
sparse = win.find("Allocate", "check box")
lib.utils.check(lambda: not sparse.checked)
finish.click()
# Delete it, clicking 'No' first
volcell = vollist.find(newname + ".qcow2")
volcell.click()
volcell.bring_on_screen()
hostwin.find("vol-refresh", "push button").click()
hostwin.find("vol-delete", "push button").click()
app.click_alert_button("permanently delete the volume", "No")
@ -92,20 +92,8 @@ def testCreateVolMisc(app):
# Using previous name so we collide
name.set_text(newname)
win.combo_select("Format:", "raw")
cap = win.find("Max Capacity:", "spin button")
alloc = win.find("Allocation:", "spin button")
alloc.set_text("50.0")
alloc.click()
app.rawinput.pressKey("Enter")
lib.utils.check(lambda: cap.text == "50.0")
cap.set_text("1.0")
cap.click()
app.rawinput.pressKey("Enter")
lib.utils.check(lambda: alloc.text == "1.0")
alloc.set_text("0.5")
alloc.click()
app.rawinput.pressKey("Enter")
lib.utils.check(lambda: cap.text == "1.0")
sparse = win.find("Allocate", "check box")
lib.utils.check(lambda: sparse.checked)
finish.click()
app.click_alert_button("Error validating volume", "Close")
@ -122,6 +110,7 @@ def testCreateVolMisc(app):
win.find("Backing store").click_expander()
win.find("Browse...").click()
app.select_storagebrowser_volume("disk-pool", "diskvol7")
sparse.check_not_onscreen()
finish.click()
vollist.find(newname)

View File

@ -142,7 +142,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">True</property>
<property name="row_spacing">4</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkBox" id="hbox10">
@ -284,8 +284,7 @@
<object class="GtkGrid" id="table2">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="border_width">8</property>
<property name="row_spacing">4</property>
<property name="row_spacing">6</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkSpinButton" id="vol-capacity">
@ -297,42 +296,12 @@
<property name="climb_rate">10</property>
<property name="digits">1</property>
<property name="value">1</property>
<signal name="value-changed" handler="on_vol_capacity_value_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">0</property>
</packing>
</child>
<child>
<object class="GtkSpinButton" id="vol-allocation">
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
<property name="text" translatable="yes">1.0</property>
<property name="adjustment">adjustment1</property>
<property name="climb_rate">10</property>
<property name="digits">1</property>
<property name="value">1</property>
<signal name="value-changed" handler="on_vol_allocation_value_changed" swapped="no"/>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label9">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">GiB</property>
</object>
<packing>
<property name="left_attach">2</property>
<property name="top_attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label8">
<property name="visible">True</property>
@ -350,7 +319,7 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Max Ca_pacity:</property>
<property name="label" translatable="yes">Ca_pacity:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">vol-capacity</property>
</object>
@ -360,13 +329,27 @@
</packing>
</child>
<child>
<object class="GtkLabel" id="label7">
<object class="GtkCheckButton" id="vol-nonsparse">
<property name="label" translatable="yes">_Allocate entire volume now</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">False</property>
<property name="use_underline">True</property>
<property name="draw_indicator">True</property>
</object>
<packing>
<property name="left_attach">1</property>
<property name="top_attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkAlignment">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">_Allocation:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">vol-allocation</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="left_attach">0</property>
@ -391,16 +374,20 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="vexpand">False</property>
<property name="expanded">True</property>
<child>
<object class="GtkGrid" id="grid1">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="margin_top">4</property>
<property name="column_spacing">6</property>
<child>
<object class="GtkLabel" id="label11">
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="label" translatable="yes">Path:</property>
<property name="label" translatable="yes">Pa_th:</property>
<property name="use_underline">True</property>
<property name="mnemonic_widget">backing-store</property>
</object>
<packing>
<property name="left_attach">0</property>
@ -412,7 +399,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="hexpand">True</property>
<signal name="changed" handler="on_backing_store_changed" swapped="no"/>
<child internal-child="accessible">
<object class="AtkObject" id="backing-store-atkobject">
<property name="AtkObject::accessible-name">backing-store</property>
@ -426,11 +412,12 @@
</child>
<child>
<object class="GtkButton" id="backing-browse">
<property name="label" translatable="yes">Browse...</property>
<property name="label" translatable="yes">_Browse...</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="receives_default">True</property>
<property name="image">image2</property>
<property name="use_underline">True</property>
<signal name="clicked" handler="on_backing_browse_clicked" swapped="no"/>
</object>
<packing>
@ -445,7 +432,8 @@
<property name="visible">True</property>
<property name="can_focus">False</property>
<property name="hexpand">False</property>
<property name="label" translatable="yes">Backing store</property>
<property name="label" translatable="yes">_Backing store</property>
<property name="use_underline">True</property>
</object>
</child>
</object>

View File

@ -41,9 +41,6 @@ class vmmCreateVolume(vmmGObjectUI):
"on_vol_name_changed": self._vol_name_changed_cb,
"on_vol_format_changed": self._vol_format_changed_cb,
"on_backing_store_changed": self._backing_storage_changed_cb,
"on_vol_allocation_value_changed": self._vol_allocation_changed_cb,
"on_vol_capacity_value_changed": self._vol_capacity_changed_cb,
"on_backing_browse_clicked": self._browse_backing_clicked_cb,
})
self.bind_escape_key_close()
@ -127,22 +124,17 @@ class vmmCreateVolume(vmmGObjectUI):
self.widget("vol-name").grab_focus()
self.widget("vol-name").emit("changed")
default_alloc = 0
default_cap = 20
self.widget("backing-store").set_text("")
alloc = default_alloc
if not self._can_alloc():
alloc = default_cap
self._show_alloc()
self.widget("vol-nonsparse").set_active(
not self._should_default_sparse())
self._show_sparse()
self._show_backing()
self.widget("backing-expander").set_expanded(False)
self.widget("vol-allocation").set_range(0,
int(self._parent_pool.get_available() / 1024 / 1024 / 1024))
self.widget("vol-allocation").set_value(alloc)
pool_avail = int(self._parent_pool.get_available() / 1024 / 1024 / 1024)
default_cap = 20
self.widget("vol-capacity").set_range(0.1, 1000000)
self.widget("vol-capacity").set_value(default_cap)
self.widget("vol-capacity").set_value(min(default_cap, pool_avail))
self.widget("vol-parent-info").set_markup(
_("<b>%(volume)s's</b> available space: %(size)s") % {
@ -183,25 +175,16 @@ class vmmCreateVolume(vmmGObjectUI):
return StorageVolume.get_file_extension_for_format(
self._get_config_format())
def _can_only_sparse(self):
if self._get_config_format() == "qcow2":
return True
if (self.widget("backing-store").is_visible() and
self.widget("backing-store").get_text()):
return True
return False
def _should_default_sparse(self):
return self._get_config_format() == "qcow2"
def _can_alloc(self):
if self._can_only_sparse():
return False
if self._parent_pool.get_type() == "logical":
# Sparse LVM volumes don't auto grow, so alloc=0 is useless
return False
return True
def _can_sparse(self):
dtype = self._parent_pool.xmlobj.get_disk_type()
return dtype == StorageVolume.TYPE_FILE
def _show_alloc(self):
def _show_sparse(self):
uiutil.set_grid_row_visible(
self.widget("vol-allocation"), self._can_alloc())
self.widget("vol-nonsparse"), self._can_sparse())
def _can_backing(self):
if self._parent_pool.get_type() == "logical":
@ -252,13 +235,13 @@ class vmmCreateVolume(vmmGObjectUI):
suffix = self.widget("vol-name-suffix").get_text()
volname = name + suffix
fmt = self._get_config_format()
alloc = self.widget("vol-allocation").get_value()
cap = self.widget("vol-capacity").get_value()
nonsparse = self.widget("vol-nonsparse").get_active()
backing = self.widget("backing-store").get_text()
if not self.widget("vol-allocation").get_visible():
alloc = 0
if nonsparse:
alloc = cap
if self._can_only_sparse():
alloc = 0
vol = self._make_stub_vol()
vol.name = volname
@ -341,28 +324,12 @@ class vmmCreateVolume(vmmGObjectUI):
self._xmleditor.set_xml(xmlobj and xmlobj.get_xml() or "")
def _vol_format_changed_cb(self, src):
self._show_alloc()
self._show_sparse()
self.widget("vol-nonsparse").set_active(
not self._should_default_sparse())
self._show_backing()
self.widget("vol-name").emit("changed")
def _vol_capacity_changed_cb(self, src):
alloc_widget = self.widget("vol-allocation")
cap = src.get_value()
alloc = self.widget("vol-allocation").get_value()
if cap < alloc:
alloc_widget.set_value(cap)
def _vol_allocation_changed_cb(self, src):
cap_widget = self.widget("vol-capacity")
alloc = src.get_value()
cap = cap_widget.get_value()
if alloc > cap:
cap_widget.set_value(alloc)
def _vol_name_changed_cb(self, src):
text = src.get_text()
@ -374,8 +341,5 @@ class vmmCreateVolume(vmmGObjectUI):
def _browse_backing_clicked_cb(self, src):
self._browse_file()
def _backing_storage_changed_cb(self, src):
self._show_alloc()
def _create_clicked_cb(self, src):
self._finish()