--- data/ui/autopart.glade | 49 +++++++++++++++++++++++--- pyanaconda/installclass.py | 7 ++-- pyanaconda/iw/autopart_type.py | 8 ++++ pyanaconda/storage/__init__.py | 1 + pyanaconda/storage/partitioning.py | 67 ++++++++++++++++++++++++++++++------ pyanaconda/storage/partspec.py | 10 ++++-- 6 files changed, 120 insertions(+), 22 deletions(-) diff --git a/data/ui/autopart.glade b/data/ui/autopart.glade index ce41778..b1346f6 100644 --- a/data/ui/autopart.glade +++ b/data/ui/autopart.glade @@ -24,7 +24,7 @@ <child> <widget class="GtkTable" id="parttypeTable"> <property name="visible">True</property> - <property name="n_rows">4</property> + <property name="n_rows">5</property> <property name="n_columns">1</property> <property name="homogeneous">False</property> <property name="row_spacing">0</property> @@ -59,6 +59,45 @@ </child> <child> + <widget class="GtkHBox" id="hbox3"> + <property name="visible">True</property> + <property name="homogeneous">False</property> + <property name="spacing">0</property> + + <child> + <widget class="GtkCheckButton" id="lvmButton"> + <property name="visible">True</property> + <property name="can_focus">True</property> + <property name="label" translatable="yes">Use _LVM</property> + <property name="use_underline">True</property> + <property name="relief">GTK_RELIEF_NORMAL</property> + <property name="focus_on_click">True</property> + <property name="active">False</property> + <property name="inconsistent">False</property> + <property name="draw_indicator">True</property> + </widget> + <packing> + <property name="padding">0</property> + <property name="expand">False</property> + <property name="fill">False</property> + </packing> + </child> + + <child> + <placeholder/> + </child> + </widget> + <packing> + <property name="left_attach">0</property> + <property name="right_attach">1</property> + <property name="top_attach">2</property> + <property name="bottom_attach">3</property> + <property name="x_options">fill</property> + <property name="y_options">fill</property> + </packing> + </child> + + <child> <widget class="GtkHBox" id="hbox5"> <property name="visible">True</property> <property name="homogeneous">False</property> @@ -90,8 +129,8 @@ <packing> <property name="left_attach">0</property> <property name="right_attach">1</property> - <property name="top_attach">2</property> - <property name="bottom_attach">3</property> + <property name="top_attach">3</property> + <property name="bottom_attach">4</property> <property name="x_options">fill</property> <property name="y_options">fill</property> </packing> @@ -127,8 +166,8 @@ <packing> <property name="left_attach">0</property> <property name="right_attach">1</property> - <property name="top_attach">3</property> - <property name="bottom_attach">4</property> + <property name="top_attach">4</property> + <property name="bottom_attach">5</property> <property name="x_options">fill</property> <property name="y_options">fill</property> </packing> diff --git a/pyanaconda/installclass.py b/pyanaconda/installclass.py index 0819b6b..440b97c 100644 --- a/pyanaconda/installclass.py +++ b/pyanaconda/installclass.py @@ -175,9 +175,10 @@ class BaseInstallClass(object): def setDefaultPartitioning(self, storage, platform): autorequests = [PartSpec(mountpoint="/", fstype=storage.defaultFSType, size=1024, maxSize=50*1024, grow=True, - asVol=True), + asVol=True, encrypted=True), PartSpec(mountpoint="/home", fstype=storage.defaultFSType, - size=100, grow=True, asVol=True, requiredSpace=50*1024)] + size=100, grow=True, requiredSpace=50*1024, + asVol=True, encrypted=True)] bootreq = platform.setDefaultPartitioning() if bootreq: @@ -185,7 +186,7 @@ class BaseInstallClass(object): (minswap, maxswap) = iutil.swapSuggestion() autorequests.append(PartSpec(fstype="swap", size=minswap, maxSize=maxswap, - grow=True, asVol=True)) + grow=True, asVol=True, encrypted=True)) storage.autoPartitionRequests = autorequests diff --git a/pyanaconda/iw/autopart_type.py b/pyanaconda/iw/autopart_type.py index 6eef3ac..c50ba49 100644 --- a/pyanaconda/iw/autopart_type.py +++ b/pyanaconda/iw/autopart_type.py @@ -186,6 +186,11 @@ class PartitionTypeWindow(InstallWindow): self.dispatch.request_steps("autopartitionexecute", "cleardiskssel") + if self.lvmButton.get_active(): + self.storage.lvmAutoPart = True + else: + self.storage.lvmAutoPart = False + if self.encryptButton.get_active(): self.storage.encryptedAutoPart = True else: @@ -241,11 +246,13 @@ class PartitionTypeWindow(InstallWindow): (self.xml, vbox) = gui.getGladeWidget("autopart.glade", "parttypeTable") self.encryptButton = self.xml.get_widget("encryptButton") self.reviewButton = self.xml.get_widget("reviewButton") + self.lvmButton = self.xml.get_widget("lvmButton") self.table = self.xml.get_widget("parttypeTable") self.prevrev = None self.reviewButton.set_active(self.dispatch.step_enabled("partition")) self.encryptButton.set_active(self.storage.encryptedAutoPart) + self.lvmButton.set_active(self.storage.lvmAutoPart) self.buttonGroup = pixmapRadioButtonGroup() self.buttonGroup.addEntry("all", _("Use _All Space"), @@ -306,5 +313,6 @@ class PartitionTypeWindow(InstallWindow): self.reviewButton.set_active(True) self.reviewButton.set_sensitive(False) self.encryptButton.set_sensitive(False) + self.lvmButton.set_sensitive(False) return vbox diff --git a/pyanaconda/storage/__init__.py b/pyanaconda/storage/__init__.py index a2bfc12..74bcfb1 100644 --- a/pyanaconda/storage/__init__.py +++ b/pyanaconda/storage/__init__.py @@ -349,6 +349,7 @@ class Storage(object): self.doAutoPart = False self.clearPartChoice = None self.encryptedAutoPart = False + self.lvmAutoPart = False self.encryptionPassphrase = None self.escrowCertificates = {} self.autoPartEscrowCert = None diff --git a/pyanaconda/storage/partitioning.py b/pyanaconda/storage/partitioning.py index 25aa169..6cb9c92 100644 --- a/pyanaconda/storage/partitioning.py +++ b/pyanaconda/storage/partitioning.py @@ -40,9 +40,8 @@ _ = lambda x: gettext.ldgettext("anaconda", x) import logging log = logging.getLogger("storage") -def _createFreeSpacePartitions(storage): - # get a list of disks that have at least one free space region of at - # least the default size for new partitions +def _getCandidateDisks(storage): + """ Return a list of disks with space for a default-sized partition. """ disks = [] for disk in storage.partitioned: if storage.config.clearPartDisks and \ @@ -61,8 +60,17 @@ def _createFreeSpacePartitions(storage): part = part.nextPartition() + return disks + +def _schedulePVs(storage, disks): + """ Schedule creation of an lvm pv partition on each disk in disks. """ # create a separate pv partition for each disk with free space devs = [] + + # only schedule PVs if there are LV autopart reqs + if not storage.lvmAutoPart: + return devs + for disk in disks: if storage.encryptedAutoPart: fmt_type = "luks" @@ -78,17 +86,32 @@ def _createFreeSpacePartitions(storage): storage.createDevice(part) devs.append(part) - return (disks, devs) + return devs def _schedulePartitions(storage, disks): - # - # Convert storage.autoPartitionRequests into Device instances and - # schedule them for creation + """ Schedule creation of autopart partitions. """ + # basis for requests with requiredSpace is the sum of the sizes of the + # two largest free regions + all_free = getFreeRegions(disks) + all_free.sort(key=lambda f: f.length, reverse=True) + if not all_free: + # this should never happen since we've already filtered the disks + # to those with at least 500MB free + log.error("no free space on disks %s" % ([d.name for d in disks],)) + return + + free = all_free[0].getSize() + if len(all_free) > 1: + free += all_free[1].getSize() + # # First pass is for partitions only. We'll do LVs later. # for request in storage.autoPartitionRequests: - if request.asVol: + if request.asVol and storage.lvmAutoPart: + continue + + if request.requiredSpace and request.requiredSpace > free: continue if request.fstype is None: @@ -119,7 +142,12 @@ def _schedulePartitions(storage, disks): if request.mountpoint == "/" and storage.liveImage: request.fstype = storage.liveImage.format.type - dev = storage.newPartition(fmt_type=request.fstype, + if request.encrypted and storage.encryptedAutoPart: + fstype = "luks" + else: + fstype = request.fstype + + dev = storage.newPartition(fmt_type=fstype, size=request.size, grow=request.grow, maxsize=request.maxSize, @@ -130,10 +158,24 @@ def _schedulePartitions(storage, disks): # schedule the device for creation storage.createDevice(dev) + if request.encrypted and storage.encryptedAutoPart: + luks_fmt = getFormat(request.fstype, + device=dev.path, + mountpoint=request.mountpoint) + luks_dev = LUKSDevice("luks-%s" % dev.name, + format=luks_fmt, + size=dev.size, + parents=dev) + storage.createDevice(luks_dev) + # make sure preexisting broken lvm/raid configs get out of the way return def _scheduleLVs(storage, devs): + """ Schedule creation of autopart lvm lvs. """ + if not devs: + return + if storage.encryptedAutoPart: pvs = [] for dev in devs: @@ -158,7 +200,7 @@ def _scheduleLVs(storage, devs): # # Second pass, for LVs only. for request in storage.autoPartitionRequests: - if not request.asVol: + if not request.asVol or not storage.lvmAutoPart: continue if request.requiredSpace and request.requiredSpace > initialVGSize: @@ -188,6 +230,8 @@ def _scheduleLVs(storage, devs): def doAutoPartition(anaconda): log.debug("doAutoPartition(%s)" % anaconda) log.debug("doAutoPart: %s" % anaconda.storage.doAutoPart) + log.debug("encryptedAutoPart: %s" % anaconda.storage.encryptedAutoPart) + log.debug("lvmAutoPart: %s" % anaconda.storage.lvmAutoPart) log.debug("clearPartType: %s" % anaconda.storage.config.clearPartType) log.debug("clearPartDisks: %s" % anaconda.storage.config.clearPartDisks) log.debug("autoPartitionRequests: %s" % anaconda.storage.autoPartitionRequests) @@ -208,7 +252,8 @@ def doAutoPartition(anaconda): anaconda.bootloader.clear_drive_list() if anaconda.storage.doAutoPart: - (disks, devs) = _createFreeSpacePartitions(anaconda.storage) + disks = _getCandidateDisks(anaconda.storage) + devs = _schedulePVs(anaconda.storage, disks) if disks == []: if anaconda.ksdata: diff --git a/pyanaconda/storage/partspec.py b/pyanaconda/storage/partspec.py index a126c3f..1602b8a 100644 --- a/pyanaconda/storage/partspec.py +++ b/pyanaconda/storage/partspec.py @@ -22,7 +22,7 @@ class PartSpec(object): def __init__(self, mountpoint=None, fstype=None, size=None, maxSize=None, grow=False, asVol=False, singlePV=False, weight=0, - requiredSpace=0): + requiredSpace=0, encrypted=False): """ Create a new storage specification. These are used to specify the default partitioning layout as an object before we have the storage system up and running. The attributes are obvious @@ -45,6 +45,9 @@ class PartSpec(object): other LVs are created inside it. If not enough space exists, this PartSpec will never get turned into an LV. + encrypted -- Should this request be encrypted? For logical volume + requests, this is satisfied if the PVs are encrypted + as in the case of encrypted LVM autopart. """ self.mountpoint = mountpoint @@ -56,6 +59,7 @@ class PartSpec(object): self.singlePV = singlePV self.weight = weight self.requiredSpace = requiredSpace + self.encrypted = encrypted if self.singlePV and not self.asVol: self.asVol = True @@ -63,12 +67,12 @@ class PartSpec(object): def __str__(self): s = ("%(type)s instance (%(id)s) -- \n" " mountpoint = %(mountpoint)s asVol = %(asVol)s singlePV = %(singlePV)s\n" - " weight = %(weight)s fstype = %(fstype)s\n" + " weight = %(weight)s fstype = %(fstype)s encrypted = %(enc)s\n" " size = %(size)s maxSize = %(maxSize)s grow = %(grow)s\n" % {"type": self.__class__.__name__, "id": "%#x" % id(self), "mountpoint": self.mountpoint, "asVol": self.asVol, "singlePV": self.singlePV, "weight": self.weight, - "fstype": self.fstype, "size": self.size, + "fstype": self.fstype, "size": self.size, "enc": self.encrypted, "maxSize": self.maxSize, "grow": self.grow}) return s -- 1.7.3.4 _______________________________________________ Anaconda-devel-list mailing list Anaconda-devel-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/anaconda-devel-list