do partitioning based on information from gadget
This commit is contained in:
parent
796f442445
commit
cf80463e5b
|
@ -174,11 +174,7 @@ for answers in examples/answers*.yaml; do
|
|||
--bootloader uefi \
|
||||
--snaps-from-examples \
|
||||
--source-catalog $catalog
|
||||
if [ "$answers" = examples/answers-tpm.yaml ]; then
|
||||
validate skip
|
||||
else
|
||||
validate install
|
||||
fi
|
||||
validate install
|
||||
grep -q 'finish: subiquity/Install/install/postinstall/run_unattended_upgrades: SUCCESS: downloading and installing security updates' $tmpdir/subiquity-server-debug.log
|
||||
else
|
||||
# The OOBE doesn't exist in WSL < 20.04
|
||||
|
|
|
@ -23,6 +23,8 @@ import platform
|
|||
import select
|
||||
from typing import List
|
||||
|
||||
from curtin.storage_config import ptable_uuid_to_flag_entry
|
||||
|
||||
import pyudev
|
||||
|
||||
from subiquitycore.async_helpers import (
|
||||
|
@ -80,6 +82,7 @@ from subiquity.models.filesystem import (
|
|||
from subiquity.server.controller import (
|
||||
SubiquityController,
|
||||
)
|
||||
from subiquity.server import snapdapi
|
||||
from subiquity.server.types import InstallerChannels
|
||||
|
||||
|
||||
|
@ -409,11 +412,59 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
|||
core_boot_classic_error=self._core_boot_classic_error,
|
||||
storage_encryption=se)
|
||||
|
||||
def _add_structure(self, *, disk: Disk, next_offset: int, is_last: bool,
|
||||
structure: snapdapi.VolumeStructure):
|
||||
ptype = structure.type.split(',', 1)[1].upper()
|
||||
if structure.offset is not None:
|
||||
offset = structure.offset
|
||||
else:
|
||||
offset = next_offset
|
||||
if structure.role == snapdapi.Role.SYSTEM_DATA and is_last:
|
||||
size = gaps.largest_gap(disk).size
|
||||
else:
|
||||
size = structure.size
|
||||
next_offset = offset + size
|
||||
flag = ptable_uuid_to_flag_entry(ptype)[0]
|
||||
part = self.model.add_partition(
|
||||
disk, offset=offset, size=size, flag=flag,
|
||||
partition_name=structure.name)
|
||||
if structure.filesystem:
|
||||
part.wipe = 'superblock'
|
||||
fs = self.model.add_filesystem(
|
||||
part, structure.filesystem, label=structure.label)
|
||||
if structure.role == snapdapi.Role.SYSTEM_DATA:
|
||||
self.model.add_mount(fs, '/')
|
||||
elif structure.role == snapdapi.Role.SYSTEM_BOOT:
|
||||
self.model.add_mount(fs, '/boot')
|
||||
elif flag == 'boot':
|
||||
self.model.add_mount(fs, '/boot/efi')
|
||||
return part
|
||||
|
||||
def apply_system(self, disk_id):
|
||||
disk = self.model._one(id=disk_id)
|
||||
if len(self._system.volumes) != 1:
|
||||
raise Exception("multiple volumes not supported")
|
||||
self.reformat(disk)
|
||||
[volume] = self._system.volumes.values()
|
||||
|
||||
next_offset = disk.alignment_data().min_start_offset
|
||||
for structure in volume.structure:
|
||||
if structure.role == snapdapi.Role.MBR:
|
||||
continue
|
||||
if ',' not in structure.type:
|
||||
continue
|
||||
part = self._add_structure(
|
||||
disk=disk,
|
||||
next_offset=next_offset,
|
||||
is_last=structure == volume.structure[-1],
|
||||
structure=structure)
|
||||
next_offset = part.offset + part.size
|
||||
disk._partitions.sort(key=lambda p: p.number)
|
||||
|
||||
async def guided_POST(self, data: GuidedChoice) -> StorageResponse:
|
||||
log.debug(data)
|
||||
if self._system is not None:
|
||||
# Here is where we will apply the gadget info from the
|
||||
# system to the disk!
|
||||
self.apply_system(data.disk_id)
|
||||
await self.configured()
|
||||
else:
|
||||
self.guided(GuidedChoiceV2.from_guided_choice(data))
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import copy
|
||||
import json
|
||||
from unittest import mock, TestCase, IsolatedAsyncioTestCase
|
||||
|
||||
from parameterized import parameterized
|
||||
|
@ -35,7 +36,7 @@ from subiquity.models.tests.test_filesystem import (
|
|||
make_model,
|
||||
make_partition,
|
||||
)
|
||||
|
||||
from subiquity.server import snapdapi
|
||||
|
||||
bootloaders = [(bl, ) for bl in list(Bootloader)]
|
||||
bootloaders_and_ptables = [(bl, pt)
|
||||
|
@ -457,3 +458,63 @@ class TestGuidedV2(IsolatedAsyncioTestCase):
|
|||
self.assertEqual(
|
||||
disk_size - (1 << 20), parts[-1].offset + parts[-1].size,
|
||||
disk_size)
|
||||
|
||||
|
||||
class TestApplySystem(TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.app = make_app()
|
||||
self.app.opts.bootloader = 'UEFI'
|
||||
self.app.report_start_event = mock.Mock()
|
||||
self.app.report_finish_event = mock.Mock()
|
||||
self.app.prober = mock.Mock()
|
||||
self.fsc = FilesystemController(app=self.app)
|
||||
self.fsc._configured = True
|
||||
self.fsc.model = make_model(Bootloader.UEFI)
|
||||
|
||||
def test_add_structure(self):
|
||||
disk = make_disk(self.fsc.model)
|
||||
part = self.fsc._add_structure(
|
||||
disk=disk,
|
||||
next_offset=disk.alignment_data().min_start_offset,
|
||||
is_last=False,
|
||||
structure=snapdapi.VolumeStructure(
|
||||
name='ptname',
|
||||
type="83,0FC63DAF-8483-4772-8E79-3D69D8477DE4",
|
||||
label='label',
|
||||
size=1 << 20,
|
||||
role=snapdapi.Role.SYSTEM_DATA,
|
||||
filesystem='ext4'))
|
||||
self.assertEqual(part.offset, disk.alignment_data().min_start_offset)
|
||||
self.assertEqual(part.partition_name, 'ptname')
|
||||
self.assertEqual(part.size, 1 << 20)
|
||||
self.assertEqual(part.fs().fstype, 'ext4')
|
||||
self.assertEqual(part.fs().mount().path, '/')
|
||||
self.assertEqual(part.wipe, 'superblock')
|
||||
|
||||
def test_add_structure_no_fs(self):
|
||||
disk = make_disk(self.fsc.model)
|
||||
part = self.fsc._add_structure(
|
||||
disk=disk,
|
||||
next_offset=disk.alignment_data().min_start_offset,
|
||||
is_last=False,
|
||||
structure=snapdapi.VolumeStructure(
|
||||
type="83,0FC63DAF-8483-4772-8E79-3D69D8477DE4",
|
||||
size=1 << 20,
|
||||
filesystem=None))
|
||||
self.assertEqual(part.size, 1 << 20)
|
||||
self.assertEqual(part.fs(), None)
|
||||
self.assertEqual(part.wipe, None)
|
||||
|
||||
def test_from_sample_data(self):
|
||||
self.fsc.model = model = make_model(Bootloader.UEFI)
|
||||
disk = make_disk(model)
|
||||
with open('examples/snaps/v2-systems-unavailable.json') as fp:
|
||||
self.fsc._system = snapdapi.snapd_serializer.deserialize(
|
||||
snapdapi.SystemDetails, json.load(fp)['result'])
|
||||
self.fsc.apply_system(disk.id)
|
||||
self.assertEqual(
|
||||
len(self.fsc._system.volumes['pc'].structure) - 1,
|
||||
len(disk.partitions()))
|
||||
mounts = {m.path for m in model._all(type='mount')}
|
||||
self.assertEqual(mounts, {'/', '/boot', '/boot/efi'})
|
||||
|
|
|
@ -252,7 +252,7 @@ def make_api_client(async_snapd):
|
|||
content = await async_snapd.get(path[1:], **params)
|
||||
else:
|
||||
content = await async_snapd.post(path[1:], json, **params)
|
||||
response = serializer.deserialize(Response, content)
|
||||
response = snapd_serializer.deserialize(Response, content)
|
||||
if response.type == ResponseType.SYNC:
|
||||
content = content['result']
|
||||
elif response.type == ResponseType.ASYNC:
|
||||
|
@ -261,10 +261,11 @@ def make_api_client(async_snapd):
|
|||
yield _FakeError()
|
||||
yield _FakeResponse(content)
|
||||
|
||||
serializer = Serializer(
|
||||
ignore_unknown_fields=True, serialize_enums_by='value')
|
||||
return make_client(SnapdAPI, make_request, serializer=snapd_serializer)
|
||||
|
||||
return make_client(SnapdAPI, make_request, serializer=serializer)
|
||||
|
||||
snapd_serializer = Serializer(
|
||||
ignore_unknown_fields=True, serialize_enums_by='value')
|
||||
|
||||
|
||||
async def post_and_wait(client, meth, *args, **kw):
|
||||
|
|
Loading…
Reference in New Issue