Don't allow multiple devices to be bootable

- Update filesystem model to check if we have an existing device
that's marked bootable.
- Update look at all disk mount points, not just the current one

Signed-off-by: Ryan Harper <ryan.harper@canonical.com>
This commit is contained in:
Ryan Harper 2015-10-02 13:49:10 -05:00
parent a0b3471084
commit ee8e25818a
5 changed files with 54 additions and 31 deletions

View File

@ -102,8 +102,13 @@ class FilesystemController(ControllerPolicy):
log.debug('disk.freespace: {}'.format(current_disk.freespace))
try:
''' create a gpt boot partition if one doesn't exist '''
if current_disk.parttype == 'gpt' and \
''' create a gpt boot partition if one doesn't exist, only
one one disk'''
system_bootable = self.model.bootable()
log.debug('model has bootable device? {}'.format(system_bootable))
if system_bootable is False and \
current_disk.parttype == 'gpt' and \
len(current_disk.disk.partitions) == 0:
if self.is_uefi():
log.debug('Adding EFI partition first')

View File

@ -171,7 +171,7 @@ class Blockdev():
@property
def percent_free(self):
''' return the device free percentage of the whole device'''
percent = ( int((1.0 - (self.usedspace / self.size)) * 100))
percent = (int((1.0 - (self.usedspace / self.size)) * 100))
return percent
@property
@ -194,18 +194,12 @@ class Blockdev():
space += int(action.offset)
space += int(action.size)
log.debug('{} usedspace: {}'.format(self.disk.devpath, space))
return space
@property
def freespace(self, unit='B'):
''' return amount of free space '''
used = self.usedspace
size = self.size
log.debug('{} freespace: {} - {} = {}'.format(self.disk.devpath,
size, used,
size - used))
return size - used
return self.size - self.usedspace
@property
def lastpartnumber(self):
@ -289,19 +283,14 @@ class Blockdev():
# dict to uniq the list of devices mounted
mounted_devs = {}
for mnt in re.findall('/dev/.*', mounts):
log.debug('mnt={}'.format(mnt))
(devpath, mount, *_) = mnt.split()
# resolve any symlinks
mounted_devs.update(
{os.path.realpath(devpath): mount})
log.debug('mounted_devs: {}'.format(mounted_devs))
matches = [dev for dev in mounted_devs.keys()
if dev.startswith(self.disk.devpath)]
log.debug('Checking if {} is in {}'.format(
self.disk.devpath, matches))
if len(matches) > 0:
log.debug('Device is mounted: {}'.format(matches))
return True
return False

View File

@ -29,6 +29,7 @@ class AttrDict(dict):
__getattr__ = dict.__getitem__
__setattr__ = dict.__setitem__
class FilesystemModel(ModelPolicy):
""" Model representing storage options
"""
@ -151,18 +152,27 @@ class FilesystemModel(ModelPolicy):
self.info[disk] = self.prober.get_storage_info(disk)
def get_disk(self, disk):
log.debug('probe_storage: get_disk()')
log.debug('probe_storage: get_disk({})'.format(disk))
if disk not in self.devices:
self.devices[disk] = Blockdev(disk, self.info[disk].serial,
self.info[disk].model,
size=self.info[disk].size)
return self.devices[disk]
def get_disks(self):
def get_available_disks(self):
''' currently only returns available disks '''
disks = [d for d in self.get_all_disks() if d.available]
log.debug('get_available_disks -> {}'.format(
",".join([d.devpath for d in disks])))
return disks
def get_all_disks(self):
possible_devices = list(set(list(self.devices.keys()) +
list(self.info.keys())))
possible_disks = [self.get_disk(d) for d in sorted(possible_devices)]
return [d for d in possible_disks if d.available]
log.debug('get_all_disks -> {}'.format(",".join([d.devpath for d in
possible_disks])))
return possible_disks
def calculate_raid_size(self, raid_level, raid_devices, spare_devices):
'''
@ -290,20 +300,39 @@ class FilesystemModel(ModelPolicy):
''' one or more disks has used space
and has "/" as a mount
'''
for disk in self.get_disks():
for disk in self.get_all_disks():
if disk.usedspace > 0 and "/" in disk.mounts:
return True
def get_available_disks(self):
return [dev.disk.devpath for dev in self.get_disks()]
def bootable(self):
''' true if one disk has a boot partition '''
log.debug('bootable check')
for disk in self.get_all_disks():
for (num, action) in disk.partitions.items():
if action.flags in ['bios_grub']:
log.debug('bootable check: we\'ve got boot!')
return True
def get_used_disks(self):
return [dev.disk.devpath for dev in self.devices.values()
log.debug('bootable check: no disks have been marked bootable')
return False
def get_available_disk_names(self):
return [dev.disk.devpath for dev in self.get_available_disks()]
def get_used_disk_names(self):
return [dev.disk.devpath for dev in self.get_all_disks()
if dev.available is False]
def get_disk_info(self, disk):
return self.info.get(disk, {})
def get_mounts(self):
mounts = []
for dev in self.get_all_disks():
mounts += dev.mounts
return mounts
def get_disk_action(self, disk):
return self.devices[disk].get_actions()

View File

@ -241,9 +241,10 @@ class AddPartitionView(WidgetWrap):
self.selected_disk)
return
# Validate mountpoint input
if self.mountpoint.value in self.selected_disk.mounts:
all_mounts = self.model.get_mounts()
if self.mountpoint.value in all_mounts:
log.error('provided mountpoint already allocated'
' ({}'.format(self.mountpoint.value))
' ({})'.format(self.mountpoint.value))
# FIXME: update the error message widget instead
self.mountpoint.set_error('ERROR: already mounted')
self.signal.emit_signal(
@ -398,7 +399,7 @@ class FilesystemView(ViewPolicy):
def _build_used_disks(self):
log.debug('FileSystemView: building used disks')
pl = []
for disk in self.model.get_used_disks():
for disk in self.model.get_used_disk_names():
log.debug('used disk: {}'.format(disk))
pl.append(Text(disk))
if len(pl):
@ -440,7 +441,7 @@ class FilesystemView(ViewPolicy):
buttons = []
# don't enable done botton if we can't install
if self.model.installable:
if self.model.installable():
buttons.append(
Color.button(done_btn(on_press=self.done),
focus_map='button focus'))
@ -464,7 +465,7 @@ class FilesystemView(ViewPolicy):
col_1 = []
col_2 = []
avail_disks = self.model.get_available_disks()
avail_disks = self.model.get_available_disk_names()
if len(avail_disks) == 0:
return Pile([Color.info_minor(Text("No available disks."))])

View File

@ -47,9 +47,8 @@ class RaidView(ViewPolicy):
items = [
Text("DISK SELECTION")
]
avail_disks = self.model.get_available_disks()
avail_disks = self.model.get_available_disk_names()
if len(avail_disks) == 0:
self.installable = False
return items.append(
[Color.info_minor(Text("No available disks."))])