allow system definition to be in live layer

Rather than always assuming it has to be mounted in from the layer to be
installed (snapd will now populate the seed in the target system when
its install API is called if it is empty).
This commit is contained in:
Michael Hudson-Doyle 2024-05-06 14:41:38 +02:00
parent c6a1b583de
commit c7fd905c6b
4 changed files with 90 additions and 13 deletions

View File

@ -0,0 +1,43 @@
{
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"systems": [
{
"current": true,
"label": "20240314",
"model": {
"model": "ubuntu-core-24-amd64-dangerous",
"brand-id": "canonical",
"display-name": "ubuntu-core-24-amd64-dangerous"
},
"brand": {
"id": "canonical",
"username": "canonical",
"display-name": "Canonical",
"validation": "verified"
},
"actions": [
{
"title": "Reinstall",
"mode": "install"
},
{
"title": "Recover",
"mode": "recover"
},
{
"title": "Factory reset",
"mode": "factory-reset"
},
{
"title": "Run normally",
"mode": "run"
}
],
"default-recovery-system": true
}
]
}
}

View File

@ -337,6 +337,15 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
self._source_handler = None
async def _get_system(self, variation_name, label):
systems = await self.app.snapdapi.v2.systems.GET()
labels = {system.label for system in systems.systems}
if label in labels:
try:
system = await self.app.snapdapi.v2.systems[label].GET()
except requests.exceptions.HTTPError as http_err:
log.warning("v2/systems/%s returned %s", label, http_err.response.text)
raise
else:
try:
await self._mount_systems_dir(variation_name)
except NoSnapdSystemsOnSource:
@ -858,6 +867,9 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
async def guided_core_boot(self, disk: Disk):
# Formatting for a core boot classic system relies on some curtin
# features that are only available with v2 partitioning.
systems = await self.app.snapdapi.v2.systems.GET()
labels = {system.label for system in systems.systems}
if self._info.label not in labels:
await self._mount_systems_dir(self._info.name)
self.model.storage_version = 2
[volume] = self._info.system.volumes.values()

View File

@ -432,6 +432,18 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase):
},
}
requests_mocker = requests_mock.Mocker()
requests_mocker.get(
"http+unix://snapd/v2/systems",
json={
"type": "sync",
"status-code": 200,
"status": "OK",
"result": {
"systems": [],
},
},
status_code=200,
)
requests_mocker.get(
"http+unix://snapd/v2/systems/enhanced-secureboot-desktop",
json=json_body,
@ -1397,9 +1409,10 @@ class TestCoreBootInstallMethods(IsolatedAsyncioTestCase):
name="foo",
label="system",
system=snapdapi.SystemDetails(
label="system",
volumes={
"pc": snapdapi.Volume(schema="gpt", structure=structures),
}
},
),
)

View File

@ -203,6 +203,7 @@ class StorageEncryption:
@attr.s(auto_attribs=True)
class SystemDetails:
label: str
current: bool = False
volumes: Dict[str, Volume] = attr.Factory(dict)
storage_encryption: Optional[StorageEncryption] = named_field(
@ -210,6 +211,11 @@ class SystemDetails:
)
@attr.s(auto_attribs=True)
class SystemsResponse:
systems: List[SystemDetails] = attr.Factory(list)
class SystemAction(enum.Enum):
INSTALL = "install"
@ -258,6 +264,9 @@ class SnapdAPI:
...
class systems:
def GET() -> SystemsResponse:
...
@path_parameter
class label:
def GET() -> SystemDetails: