Skip to content

Commit

Permalink
adds support for installing over LVM partitioned drive
Browse files Browse the repository at this point in the history
  • Loading branch information
taukakao committed Mar 29, 2024
1 parent b1b14de commit ae36730
Show file tree
Hide file tree
Showing 4 changed files with 117 additions and 19 deletions.
13 changes: 13 additions & 0 deletions vanilla_installer/core/disks.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,19 @@ def separate_device_and_partn(part_dev: str) -> tuple[str, str|None]:

return "/dev/" + info["pkname"], str(info["partn"])

@staticmethod
def fetch_lvm_pvs() -> list[list[str]]:
output_json = subprocess.check_output(
"sudo pvs --reportformat=json", shell=True
).decode("utf-8")
output_pvs = json.loads(output_json)["report"][0]["pv"]
pv_with_vgs = []
for pv_output in output_pvs:
pv_name = pv_output["pv_name"]
vg_name = pv_output["vg_name"] if pv_output["vg_name"] != "" else None
pv_with_vgs.append([pv_name, vg_name])
return pv_with_vgs

class Disk:
def __init__(self, disk: str):
self.__disk = disk
Expand Down
58 changes: 56 additions & 2 deletions vanilla_installer/defaults/disk.py
Original file line number Diff line number Diff line change
Expand Up @@ -518,16 +518,27 @@ def set_btn_apply_sensitive(self, val):
def partition_recipe(self):
recipe = {}

pv_list = Diskutils.fetch_lvm_pvs()

for __, info in self.__partition_selector.selected_partitions.items():
# Partition can be None if user didn't configure swap
if not isinstance(info["partition"], Partition):
continue

pv_to_remove = None
vg_to_remove = None
for pv, vg in pv_list:
if pv == info["partition"].partition:
pv_to_remove = pv
vg_to_remove = vg

recipe[info["partition"].partition] = {
"fs": info["fstype"],
"mp": info["mountpoint"],
"pretty_size": info["partition"].pretty_size,
"size": info["partition"].size,
"existing_pv": pv_to_remove,
"existing_vg": vg_to_remove
}

return recipe
Expand Down Expand Up @@ -557,7 +568,6 @@ def __init__(self, window, partition_recipe, **kwargs):
entry.set_title(partition_recipe[partition]["disk"])
entry.set_subtitle(_("Entire disk will be used."))
else:
self.set_default_size(self.default_width, 650)
if partition == "disk":
continue
entry.set_title(partition)
Expand All @@ -567,7 +577,39 @@ def __init__(self, window, partition_recipe, **kwargs):
partition_recipe[partition]["mp"],
)
)
self.group_partitions.add(entry)
self.group_partitions.add(entry)

if "auto" in partition_recipe:
for vg in partition_recipe["auto"]["vgs_to_remove"]:
entry = Adw.ActionRow()
entry.set_title("LVM volume group: " + vg)
entry.set_subtitle(_("Volume group will be removed."))
self.group_partitions.add(entry)
for pv in partition_recipe["auto"]["pvs_to_remove"]:
entry = Adw.ActionRow()
entry.set_title("LVM physical volume: " + pv)
entry.set_subtitle(_("Physical volume will be removed."))
self.group_partitions.add(entry)
else:
vgs_to_remove = []
for partition, values in partition_recipe.items():
if partition == "disk":
continue
pv = values["existing_pv"]
vg = values["existing_vg"]
if pv is None:
continue
if vg is not None and vg not in vgs_to_remove:
vgs_to_remove.append(values["existing_vg"])
entry = Adw.ActionRow()
entry.set_title("LVM physical volume: " + pv)
entry.set_subtitle(_("Physical volume will be removed."))
self.group_partitions.add(entry)
for vg in vgs_to_remove:
entry = Adw.ActionRow()
entry.set_title("LVM volume group: " + vg)
entry.set_subtitle(_("Volume group will be removed."))
self.group_partitions.add(entry)

def __on_btn_cancel_clicked(self, widget):
self.destroy()
Expand Down Expand Up @@ -626,11 +668,23 @@ def __on_modal_close_request(self, *args):
self.btn_next.set_sensitive(self.__partition_recipe is not None)

def __on_auto_clicked(self, button):
pvs_to_remove = []
vgs_to_remove = []
for pv, vg in Diskutils.fetch_lvm_pvs():
pv_disk, _ = Diskutils.separate_device_and_partn(pv)
if pv_disk != self.__selected_disks[0].disk:
continue
pvs_to_remove.append(pv)
if vg is not None and vg not in vgs_to_remove:
vgs_to_remove.append(vg)

self.__partition_recipe = {
"auto": {
"disk": self.__selected_disks[0].disk,
"pretty_size": self.__selected_disks[0].pretty_size,
"size": self.__selected_disks[0].size,
"vgs_to_remove": vgs_to_remove,
"pvs_to_remove": pvs_to_remove,
}
}
modal = VanillaDefaultDiskConfirmModal(self.__window, self.__partition_recipe)
Expand Down
32 changes: 17 additions & 15 deletions vanilla_installer/gtk/dialog-disk-confirm.ui
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
<property name="modal">true</property>
<property name="deletable">false</property>
<property name="default-width">500</property>
<property name="default-height">450</property>
<property name="default-height">650</property>
<child>
<object class="GtkBox">
<property name="orientation">vertical</property>
Expand All @@ -25,25 +25,27 @@
<property name="title" translatable="yes">Confirm Changes</property>
<property name="description" translatable="yes">The following changes will be made to your disk. Please review them carefully.</property>
<child>
<object class="AdwPreferencesPage">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="spacing">20</property>
<child>
<object class="AdwPreferencesGroup" id="group_partitions"></object>
</child>
<child>
<object class="AdwPreferencesGroup">
<object class="AdwPreferencesPage">
<child>
<object class="GtkButton" id="btn_apply">
<property name="label" translatable="yes">Confirm Changes</property>
<property name="valign">center</property>
<property name="halign">center</property>
<style>
<class name="destructive-action"/>
<class name="pill"/>
</style>
</object>
<object class="AdwPreferencesGroup" id="group_partitions"></object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="btn_apply">
<property name="label" translatable="yes">Confirm Changes</property>
<property name="valign">center</property>
<property name="halign">center</property>
<style>
<class name="destructive-action"/>
<class name="pill"/>
</style>
</object>
</child>
</object>
</child>
</object>
Expand Down
33 changes: 31 additions & 2 deletions vanilla_installer/utils/processor.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,12 +242,20 @@ def merge_postinstall_steps(self):
class Processor:
@staticmethod
def __gen_auto_partition_steps(
disk: str, encrypt: bool, root_size: int, password: str | None = None
disk: str, encrypt: bool, root_size: int,
existing_pvs: list[str] | None, existing_vgs: list[str] | None,
password: str | None = None,
):
setup_steps = []
mountpoints = []
post_install_steps = []

# Before we do anything, we need to remove conflicting LVM objects
for vg in existing_vgs:
setup_steps.append([disk, "vgremove", [vg]])
for pv in existing_pvs:
setup_steps.append([disk, "pvremove", [pv]])

setup_steps.append([disk, "label", ["gpt"]])
# Boot
setup_steps.append([disk, "mkpart", ["vos-boot", "ext4", 1, 1025]])
Expand Down Expand Up @@ -323,6 +331,25 @@ def __gen_manual_partition_steps(
mountpoints = []
post_install_steps = []

# Before we do anything, we need to remove conflicting LVM objects
vgs_to_remove = []
pvs_to_remove = []
for part, values in disk_final.items():
pv = values["existing_pv"]
vg = values["existing_vg"]
if pv is None:
continue
disk, _ = Diskutils.separate_device_and_partn(pv)
pvs_to_remove.append([pv, disk])
if vg is not None and vg not in vgs_to_remove:
vgs_to_remove.append([vg, disk])

for vg, disk in vgs_to_remove:
setup_steps.append([disk, "vgremove", [vg]])
for pv, disk in pvs_to_remove:
setup_steps.append([disk, "pvremove", [pv]])


# Since manual partitioning uses GParted to handle partitions (for now),
# we don't need to create any partitions or label disks (for now).
# But we still need to format partitions.
Expand Down Expand Up @@ -459,7 +486,9 @@ def gen_install_recipe(log_path, finals, sys_recipe):
if "disk" in final.keys():
if "auto" in final["disk"].keys():
part_info = Processor.__gen_auto_partition_steps(
final["disk"]["auto"]["disk"], encrypt, root_size, password
final["disk"]["auto"]["disk"], encrypt, root_size,
final["disk"]["auto"]["pvs_to_remove"], final["disk"]["auto"]["vgs_to_remove"],
password,
)
else:
part_info = Processor.__gen_manual_partition_steps(
Expand Down

0 comments on commit ae36730

Please sign in to comment.