Merge pull request #398 from mwhudson/md-name-validation

validate raid and vg/lv names
This commit is contained in:
Michael Hudson-Doyle 2018-11-23 09:38:27 +13:00 committed by GitHub
commit 583909a716
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 106 additions and 9 deletions

View File

@ -14,6 +14,8 @@
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import logging
import os
import re
from urwid import (
connect_signal,
@ -25,7 +27,11 @@ from subiquitycore.ui.container import (
)
from subiquitycore.ui.form import (
ReadOnlyField,
StringField,
simple_field,
WantsToKnowFormField,
)
from subiquitycore.ui.interactive import (
StringEditor,
)
from subiquitycore.ui.stretchy import (
Stretchy,
@ -44,13 +50,33 @@ from subiquity.ui.views.filesystem.compound import (
log = logging.getLogger('subiquity.ui.lvm')
class VGNameEditor(StringEditor, WantsToKnowFormField):
def __init__(self):
self.valid_char_pat = r'[-a-zA-Z0-9_+.]'
self.error_invalid_char = _("The only characters permitted in the "
"name of a volume group are a-z, A-Z, "
"0-9, +, _, . and -")
super().__init__()
def valid_char(self, ch):
if len(ch) == 1 and not re.match(self.valid_char_pat, ch):
self.bff.in_error = True
self.bff.show_extra(("info_error", self.error_invalid_char))
return False
else:
return super().valid_char(ch)
VGNameField = simple_field(VGNameEditor)
class VolGroupForm(CompoundDiskForm):
def __init__(self, model, possible_components, initial, vg_names):
self.vg_names = vg_names
super().__init__(model, possible_components, initial)
name = StringField(_("Name:"))
name = VGNameField(_("Name:"))
devices = MultiDeviceField(_("Devices:"))
size = ReadOnlyField(_("Size:"))
@ -60,7 +86,15 @@ class VolGroupForm(CompoundDiskForm):
"group.")
def validate_name(self):
if self.name.value in self.vg_names:
v = self.name.value
if not v:
return _("The name of a volume group cannot be empty")
if v.startswith('-'):
return _("The name of a volume group cannot start with a hyphen")
if v in ('.', '..', 'md') or os.path.exists('/dev/' + v):
return _("{} is not a valid name for a volume group").format(
v)
if v in self.vg_names:
return _("There is already a volume group named '{}'").format(
self.name.value)

View File

@ -20,13 +20,15 @@ configuration.
"""
import logging
import re
from urwid import connect_signal, Text
from subiquitycore.ui.form import (
Form,
FormField,
StringField,
simple_field,
WantsToKnowFormField,
)
from subiquitycore.ui.interactive import StringEditor
from subiquitycore.ui.selector import Option, Selector
@ -92,6 +94,26 @@ class SizeField(FormField):
return SizeWidget(form)
class LVNameEditor(StringEditor, WantsToKnowFormField):
def __init__(self):
self.valid_char_pat = r'[-a-zA-Z0-9_+.]'
self.error_invalid_char = _("The only characters permitted in the "
"name of a logical volume are a-z, A-Z, "
"0-9, +, _, . and -")
super().__init__()
def valid_char(self, ch):
if len(ch) == 1 and not re.match(self.valid_char_pat, ch):
self.bff.in_error = True
self.bff.show_extra(("info_error", self.error_invalid_char))
return False
else:
return super().valid_char(ch)
LVNameField = simple_field(LVNameEditor)
class PartitionForm(Form):
def __init__(self, mountpoints, max_size, initial, ok_for_slash_boot,
@ -112,7 +134,7 @@ class PartitionForm(Form):
def select_fstype(self, sender, fs):
self.mount.enabled = fs.is_mounted
name = StringField(_("Name: "))
name = LVNameField(_("Name: "))
size = SizeField()
fstype = FSTypeField(_("Format:"))
mount = MountField(_("Mount:"))
@ -135,8 +157,20 @@ class PartitionForm(Form):
return None
def validate_name(self):
log.debug("validate_name %s %s", self.name.value, self.lvm_names)
if self.name.value in self.lvm_names:
v = self.name.value
if not v:
return _("The name of a logical volume cannot be empty")
if v.startswith('-'):
return _("The name of a logical volume cannot start with a hyphen")
if v in ('.', '..', 'snapshot', 'pvmove'):
return _("A logical volume may not be called {}").format(v)
for substring in ['_cdata', '_cmeta', '_corig', '_mlog', '_mimage',
'_pmspare', '_rimage', '_rmeta', '_tdata',
'_tmeta', '_vorigin']:
if substring in v:
return _('The name of a logical volume may not contain '
'"{}"').format(substring)
if v in self.lvm_names:
return _("There is already a logical volume named {}.").format(
self.name.value)

View File

@ -27,7 +27,11 @@ from subiquitycore.ui.container import (
from subiquitycore.ui.form import (
ChoiceField,
ReadOnlyField,
StringField,
simple_field,
WantsToKnowFormField,
)
from subiquitycore.ui.interactive import (
StringEditor,
)
from subiquitycore.ui.selector import (
Option,
@ -55,18 +59,41 @@ raidlevel_choices = [
Option((_(level.name), True, level)) for level in raidlevels]
class RaidnameEditor(StringEditor, WantsToKnowFormField):
def valid_char(self, ch):
if len(ch) == 1 and ch == '/':
self.bff.in_error = True
self.bff.show_extra(("info_error",
_("/ is not permitted "
"in the name of a RAID device")))
return False
elif len(ch) == 1 and ch.isspace():
self.bff.in_error = True
self.bff.show_extra(("info_error",
_("Whitespace is not permitted in the "
"name of a RAID device")))
return False
else:
return super().valid_char(ch)
RaidnameField = simple_field(RaidnameEditor)
class RaidForm(CompoundDiskForm):
def __init__(self, model, possible_components, initial, raid_names):
self.raid_names = raid_names
super().__init__(model, possible_components, initial)
name = StringField(_("Name:"))
name = RaidnameField(_("Name:"))
level = ChoiceField(_("RAID Level:"), choices=raidlevel_choices)
devices = MultiDeviceField(_("Devices:"))
size = ReadOnlyField(_("Size:"))
def clean_name(self, val):
if not val:
raise ValueError("The name cannot be empty")
if not re.match('md[0-9]+', val):
val = 'md/' + val
return val
@ -75,6 +102,8 @@ class RaidForm(CompoundDiskForm):
if self.name.value in self.raid_names:
return _("There is already a RAID named '{}'").format(
self.name.value)
if self.name.value in ('/dev/md/.', '/dev/md/..'):
return _(". and .. are not valid names for RAID devices")
def validate_devices(self):
log.debug(