Initial working bcache UX connected to fs model

Panel up and adds a bcache device.

Signed-off-by: Ryan Harper <ryan.harper@canonical.com>
This commit is contained in:
Ryan Harper 2015-11-13 12:29:18 -06:00
parent d786676366
commit 0385e754ab
4 changed files with 155 additions and 8 deletions

View File

@ -17,12 +17,11 @@ import logging
import os import os
from subiquity.controller import ControllerPolicy from subiquity.controller import ControllerPolicy
from subiquity.models.actions import preserve_action from subiquity.models.actions import preserve_action
from subiquity.models import (FilesystemModel, from subiquity.models import (FilesystemModel, RaidModel)
RaidModel)
from subiquity.models.filesystem import (_humanize_size) from subiquity.models.filesystem import (_humanize_size)
from subiquity.ui.views import (DiskPartitionView, AddPartitionView, from subiquity.ui.views import (DiskPartitionView, AddPartitionView,
AddFormatView, FilesystemView, AddFormatView, FilesystemView,
DiskInfoView, RaidView) DiskInfoView, RaidView, BcacheView)
from subiquity.ui.dummy import DummyView from subiquity.ui.dummy import DummyView
from subiquity.ui.error import ErrorView from subiquity.ui.error import ErrorView
from subiquity.curtin import (curtin_write_storage_actions, from subiquity.curtin import (curtin_write_storage_actions,
@ -222,14 +221,23 @@ class FilesystemController(ControllerPolicy):
self.ui.set_body(RaidView(self.model, self.ui.set_body(RaidView(self.model,
self.signal)) self.signal))
def create_bcache(self, *args, **kwargs):
title = ("Create hierarchical storage (\"bcache\") disk")
footer = ("ENTER on a disk will show detailed "
"information for that disk")
excerpt = ("Use SPACE to select a cache disk and a backing disk"
" to form your bcache device.")
self.ui.set_header(title, excerpt)
self.ui.set_footer(footer)
self.ui.set_body(BcacheView(self.model,
self.signal))
def add_raid_dev(self, result): def add_raid_dev(self, result):
log.debug('add_raid_dev: result={}'.format(result)) log.debug('add_raid_dev: result={}'.format(result))
self.model.add_raid_device(result) self.model.add_raid_device(result)
self.signal.prev_signal() self.signal.prev_signal()
def setup_bcache(self, *args, **kwargs):
self.ui.set_body(DummyView(self.signal))
def add_first_gpt_partition(self, *args, **kwargs): def add_first_gpt_partition(self, *args, **kwargs):
self.ui.set_body(DummyView(self.signal)) self.ui.set_body(DummyView(self.signal))

View File

@ -248,8 +248,8 @@ class PartitionAction(DiskAction):
class BcacheAction(DiskAction): class BcacheAction(DiskAction):
def __init__(self, action_id, backing_id, cache_id): def __init__(self, action_id, backing_id, cache_id):
self.parent = None self.parent = None
self._backing_device = backing_id.parent.action_id self._backing_device = backing_id
self._cache_device = cache_id.parent.action_id self._cache_device = cache_id
self._action_id = action_id self._action_id = action_id
self._type = 'bcache' self._type = 'bcache'

View File

@ -18,6 +18,7 @@ from .filesystem import (FilesystemView, # NOQA
AddFormatView, AddFormatView,
DiskPartitionView, DiskPartitionView,
DiskInfoView) DiskInfoView)
from .bcache import BcacheView # NOQA
from .raid import RaidView # NOQA from .raid import RaidView # NOQA
from .ceph import CephDiskView # NOQA from .ceph import CephDiskView # NOQA
from .iscsi import IscsiDiskView # NOQA from .iscsi import IscsiDiskView # NOQA

View File

@ -0,0 +1,138 @@
# Copyright 2015 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from urwid import Text, Pile, ListBox
from subiquity.models.filesystem import _humanize_size
from subiquity.view import ViewPolicy
from subiquity.ui.buttons import cancel_btn, done_btn
from subiquity.ui.interactive import Selector
from subiquity.ui.utils import Color, Padding
import logging
log = logging.getLogger('subiquity.ui.bcache')
class BcacheView(ViewPolicy):
def __init__(self, model, signal):
self.model = model
self.signal = signal
self.selected_disks = {
'CACHE': None,
'BACKING': None,
}
body = [
Padding.center_50(self._build_disk_selection(section='CACHE')),
Padding.line_break(""),
Padding.center_50(self._build_disk_selection(section='BACKING')),
Padding.line_break(""),
Padding.center_20(self._build_buttons())
]
super().__init__(ListBox(body))
@property
def cache_disk(self):
selector = self.selected_disks['CACHE']
if selector:
return selector.value
return selector
@property
def backing_disk(self):
selector = self.selected_disks['BACKING']
if selector:
return selector.value
return selector
def _build_disk_selection(self, section):
log.debug('bcache: _build_disk_selection, section:' + section)
items = [
Text(section + " DISK SELECTION")
]
avail_devs = self._get_available_devs()
if len(avail_devs) == 0:
return items.append(
[Color.info_minor(Text("No available disks."))])
selector = Selector(avail_devs)
self.selected_disks[section] = selector
items.append(Color.string_input(Pile(selector.group),
focus_map="string_input focus"))
return Pile(items)
def _get_available_devs(self):
devs = []
# bcache can use empty whole disks, or empty partitions
avail_disks = self.model.get_empty_disk_names()
avail_parts = self.model.get_empty_partition_names()
# filter out currently selected cache or backing disk
selected_disks = [self.backing_disk, self.cache_disk]
avail_devs = sorted([dev for dev in (avail_disks + avail_parts)
if dev not in selected_disks])
for dname in avail_devs:
device = self.model.get_disk(dname)
if device.path != dname:
# we've got a partition
bcachedev = device.get_partition(dname)
else:
bcachedev = device
disk_sz = _humanize_size(bcachedev.size)
disk_string = "{} {}, {}".format(dname,
disk_sz,
device.model)
log.debug('bcache: disk_string={}'.format(disk_string))
devs.append(disk_string)
return devs
def _build_buttons(self):
log.debug('bcache: _build_buttons')
cancel = cancel_btn(on_press=self.cancel)
done = done_btn(on_press=self.done)
buttons = [
Color.button(done, focus_map='button focus'),
Color.button(cancel, focus_map='button focus')
]
return Pile(buttons)
def done(self, result):
result = {
'backing_device': self.backing_disk,
'cache_device': self.cache_disk,
}
if not result['backing_device']:
log.debug('Must select a backing device to create a bcache dev')
return
if not result['cache_device']:
log.debug('Must select a caching device to create a bcache dev')
return
if result['backing_device'] == result['cache_device']:
log.debug('Cannot select the same device for backing and cache')
return
log.debug('bcache_done: result = {}'.format(result))
self.model.add_bcache_device(result)
self.signal.prev_signal()
def cancel(self, button):
log.debug('bcache: button_cancel')
self.signal.prev_signal()