add the ability to only generate a subset of curtin fs actions
DEVICES == everything up to and including partitioning FORMAT_MOUNT == formatting and mounting
This commit is contained in:
parent
21407002bd
commit
cabb8dda8e
|
@ -17,6 +17,7 @@ from abc import ABC, abstractmethod
|
||||||
import attr
|
import attr
|
||||||
import collections
|
import collections
|
||||||
import copy
|
import copy
|
||||||
|
import enum
|
||||||
import fnmatch
|
import fnmatch
|
||||||
import itertools
|
import itertools
|
||||||
import logging
|
import logging
|
||||||
|
@ -1025,6 +1026,25 @@ class PartitionAlignmentData:
|
||||||
ebr_space: int = 0
|
ebr_space: int = 0
|
||||||
|
|
||||||
|
|
||||||
|
class ActionRenderMode(enum.Enum):
|
||||||
|
# The default for FilesystemModel.render() is to render actions
|
||||||
|
# for devices that have changes, but not e.g. a hard drive that
|
||||||
|
# will be untouched by the installation process.
|
||||||
|
DEFAULT = enum.auto()
|
||||||
|
# ALL means render actions for all model objects. This is used to
|
||||||
|
# send information to the client.
|
||||||
|
ALL = enum.auto()
|
||||||
|
# DEVICES means to just render actions for setting up block
|
||||||
|
# devices, e.g. partitioning disks and assembling RAIDs but not
|
||||||
|
# any format or mount actions.
|
||||||
|
DEVICES = enum.auto()
|
||||||
|
# FORMAT_MOUNT means to just render actions to format and mount
|
||||||
|
# the block devices. References to block devices will be replaced
|
||||||
|
# by "type: device" actions that just refer to the block devices
|
||||||
|
# by path.
|
||||||
|
FORMAT_MOUNT = enum.auto()
|
||||||
|
|
||||||
|
|
||||||
class FilesystemModel(object):
|
class FilesystemModel(object):
|
||||||
|
|
||||||
target = None
|
target = None
|
||||||
|
@ -1371,7 +1391,8 @@ class FilesystemModel(object):
|
||||||
|
|
||||||
return objs
|
return objs
|
||||||
|
|
||||||
def _render_actions(self, include_all=False):
|
def _render_actions(self,
|
||||||
|
mode: ActionRenderMode = ActionRenderMode.DEFAULT):
|
||||||
# The curtin storage config has the constraint that an action must be
|
# The curtin storage config has the constraint that an action must be
|
||||||
# preceded by all the things that it depends on. We handle this by
|
# preceded by all the things that it depends on. We handle this by
|
||||||
# repeatedly iterating over all actions and checking if we can emit
|
# repeatedly iterating over all actions and checking if we can emit
|
||||||
|
@ -1425,9 +1446,11 @@ class FilesystemModel(object):
|
||||||
mountpoints = {m.path: m.id for m in self.all_mounts()}
|
mountpoints = {m.path: m.id for m in self.all_mounts()}
|
||||||
log.debug('mountpoints %s', mountpoints)
|
log.debug('mountpoints %s', mountpoints)
|
||||||
|
|
||||||
|
if mode == ActionRenderMode.ALL:
|
||||||
|
work = list(self._actions)
|
||||||
|
else:
|
||||||
work = [
|
work = [
|
||||||
a for a in self._actions
|
a for a in self._actions if not getattr(a, 'preserve', False)
|
||||||
if not getattr(a, 'preserve', False) or include_all
|
|
||||||
]
|
]
|
||||||
|
|
||||||
while work:
|
while work:
|
||||||
|
@ -1444,13 +1467,29 @@ class FilesystemModel(object):
|
||||||
raise Exception("\n".join(msg))
|
raise Exception("\n".join(msg))
|
||||||
work = next_work
|
work = next_work
|
||||||
|
|
||||||
|
if mode == ActionRenderMode.DEVICES:
|
||||||
|
r = [act for act in r if act['type'] not in ('format', 'mount')]
|
||||||
|
if mode == ActionRenderMode.FORMAT_MOUNT:
|
||||||
|
r = [act for act in r if act['type'] in ('format', 'mount')]
|
||||||
|
devices = []
|
||||||
|
for act in r:
|
||||||
|
if act['type'] == 'format':
|
||||||
|
device = {
|
||||||
|
'type': 'device',
|
||||||
|
'id': 'synth-device-{}'.format(len(devices)),
|
||||||
|
'path': self._one(id=act['volume']).path,
|
||||||
|
}
|
||||||
|
devices.append(device)
|
||||||
|
act['volume'] = device['id']
|
||||||
|
r = devices + r
|
||||||
|
|
||||||
return r
|
return r
|
||||||
|
|
||||||
def render(self):
|
def render(self, mode: ActionRenderMode = ActionRenderMode.DEFAULT):
|
||||||
config = {
|
config = {
|
||||||
'storage': {
|
'storage': {
|
||||||
'version': self.storage_version,
|
'version': self.storage_version,
|
||||||
'config': self._render_actions(),
|
'config': self._render_actions(mode=mode),
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if self.swap is not None:
|
if self.swap is not None:
|
||||||
|
|
|
@ -20,6 +20,7 @@ import attr
|
||||||
from parameterized import parameterized
|
from parameterized import parameterized
|
||||||
|
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
|
ActionRenderMode,
|
||||||
Bootloader,
|
Bootloader,
|
||||||
dehumanize_size,
|
dehumanize_size,
|
||||||
Disk,
|
Disk,
|
||||||
|
@ -932,6 +933,55 @@ class TestAutoInstallConfig(unittest.TestCase):
|
||||||
self.assertTrue(disk2.id not in rendered_ids)
|
self.assertTrue(disk2.id not in rendered_ids)
|
||||||
self.assertTrue(disk2p1.id not in rendered_ids)
|
self.assertTrue(disk2p1.id not in rendered_ids)
|
||||||
|
|
||||||
|
def test_render_all_does_include_unreferenced(self):
|
||||||
|
model = make_model(Bootloader.NONE)
|
||||||
|
disk1 = make_disk(model, preserve=True)
|
||||||
|
disk2 = make_disk(model, preserve=True)
|
||||||
|
disk1p1 = make_partition(model, disk1, preserve=True)
|
||||||
|
disk2p1 = make_partition(model, disk2, preserve=True)
|
||||||
|
fs = model.add_filesystem(disk1p1, 'ext4')
|
||||||
|
model.add_mount(fs, '/')
|
||||||
|
rendered_ids = {
|
||||||
|
action['id']
|
||||||
|
for action in model._render_actions(ActionRenderMode.ALL)
|
||||||
|
}
|
||||||
|
self.assertTrue(disk1.id in rendered_ids)
|
||||||
|
self.assertTrue(disk1p1.id in rendered_ids)
|
||||||
|
self.assertTrue(disk2.id in rendered_ids)
|
||||||
|
self.assertTrue(disk2p1.id in rendered_ids)
|
||||||
|
|
||||||
|
def test_render_devices_skips_format_mount(self):
|
||||||
|
model = make_model(Bootloader.NONE)
|
||||||
|
disk1 = make_disk(model, preserve=True)
|
||||||
|
disk1p1 = make_partition(model, disk1, preserve=True)
|
||||||
|
fs = model.add_filesystem(disk1p1, 'ext4')
|
||||||
|
mnt = model.add_mount(fs, '/')
|
||||||
|
rendered_ids = {
|
||||||
|
action['id']
|
||||||
|
for action in model._render_actions(ActionRenderMode.DEVICES)
|
||||||
|
}
|
||||||
|
self.assertTrue(disk1.id in rendered_ids)
|
||||||
|
self.assertTrue(disk1p1.id in rendered_ids)
|
||||||
|
self.assertTrue(fs.id not in rendered_ids)
|
||||||
|
self.assertTrue(mnt.id not in rendered_ids)
|
||||||
|
|
||||||
|
def test_render_format_mount(self):
|
||||||
|
model = make_model(Bootloader.NONE)
|
||||||
|
disk1 = make_disk(model, preserve=True)
|
||||||
|
disk1p1 = make_partition(model, disk1, preserve=True)
|
||||||
|
disk1p1.path = '/dev/vda1'
|
||||||
|
fs = model.add_filesystem(disk1p1, 'ext4')
|
||||||
|
mnt = model.add_mount(fs, '/')
|
||||||
|
actions = model._render_actions(ActionRenderMode.FORMAT_MOUNT)
|
||||||
|
rendered_by_id = {action['id']: action for action in actions}
|
||||||
|
self.assertTrue(disk1.id not in rendered_by_id)
|
||||||
|
self.assertTrue(disk1p1.id not in rendered_by_id)
|
||||||
|
self.assertTrue(fs.id in rendered_by_id)
|
||||||
|
self.assertTrue(mnt.id in rendered_by_id)
|
||||||
|
vol_id = rendered_by_id[fs.id]['volume']
|
||||||
|
self.assertEqual(rendered_by_id[vol_id]['type'], 'device')
|
||||||
|
self.assertEqual(rendered_by_id[vol_id]['path'], '/dev/vda1')
|
||||||
|
|
||||||
def test_render_includes_all_partitions(self):
|
def test_render_includes_all_partitions(self):
|
||||||
model = make_model(Bootloader.NONE)
|
model = make_model(Bootloader.NONE)
|
||||||
disk1 = make_disk(model, preserve=True)
|
disk1 = make_disk(model, preserve=True)
|
||||||
|
|
|
@ -73,6 +73,7 @@ from subiquity.common.types import (
|
||||||
StorageResponseV2,
|
StorageResponseV2,
|
||||||
)
|
)
|
||||||
from subiquity.models.filesystem import (
|
from subiquity.models.filesystem import (
|
||||||
|
ActionRenderMode,
|
||||||
align_up,
|
align_up,
|
||||||
align_down,
|
align_down,
|
||||||
_Device,
|
_Device,
|
||||||
|
@ -370,7 +371,7 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
||||||
bootloader=self.model.bootloader,
|
bootloader=self.model.bootloader,
|
||||||
error_report=self.full_probe_error(),
|
error_report=self.full_probe_error(),
|
||||||
orig_config=self.model._orig_config,
|
orig_config=self.model._orig_config,
|
||||||
config=self.model._render_actions(include_all=True),
|
config=self.model._render_actions(mode=ActionRenderMode.ALL),
|
||||||
blockdev=self.model._probe_data['blockdev'],
|
blockdev=self.model._probe_data['blockdev'],
|
||||||
dasd=self.model._probe_data.get('dasd', {}),
|
dasd=self.model._probe_data.get('dasd', {}),
|
||||||
storage_version=self.model.storage_version)
|
storage_version=self.model.storage_version)
|
||||||
|
|
Loading…
Reference in New Issue