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:
parent
c6a1b583de
commit
c7fd905c6b
|
@ -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
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
|
@ -337,6 +337,15 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
||||||
self._source_handler = None
|
self._source_handler = None
|
||||||
|
|
||||||
async def _get_system(self, variation_name, label):
|
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:
|
try:
|
||||||
await self._mount_systems_dir(variation_name)
|
await self._mount_systems_dir(variation_name)
|
||||||
except NoSnapdSystemsOnSource:
|
except NoSnapdSystemsOnSource:
|
||||||
|
@ -858,6 +867,9 @@ class FilesystemController(SubiquityController, FilesystemManipulator):
|
||||||
async def guided_core_boot(self, disk: Disk):
|
async def guided_core_boot(self, disk: Disk):
|
||||||
# Formatting for a core boot classic system relies on some curtin
|
# Formatting for a core boot classic system relies on some curtin
|
||||||
# features that are only available with v2 partitioning.
|
# 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)
|
await self._mount_systems_dir(self._info.name)
|
||||||
self.model.storage_version = 2
|
self.model.storage_version = 2
|
||||||
[volume] = self._info.system.volumes.values()
|
[volume] = self._info.system.volumes.values()
|
||||||
|
|
|
@ -432,6 +432,18 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase):
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
requests_mocker = requests_mock.Mocker()
|
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(
|
requests_mocker.get(
|
||||||
"http+unix://snapd/v2/systems/enhanced-secureboot-desktop",
|
"http+unix://snapd/v2/systems/enhanced-secureboot-desktop",
|
||||||
json=json_body,
|
json=json_body,
|
||||||
|
@ -1397,9 +1409,10 @@ class TestCoreBootInstallMethods(IsolatedAsyncioTestCase):
|
||||||
name="foo",
|
name="foo",
|
||||||
label="system",
|
label="system",
|
||||||
system=snapdapi.SystemDetails(
|
system=snapdapi.SystemDetails(
|
||||||
|
label="system",
|
||||||
volumes={
|
volumes={
|
||||||
"pc": snapdapi.Volume(schema="gpt", structure=structures),
|
"pc": snapdapi.Volume(schema="gpt", structure=structures),
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -203,6 +203,7 @@ class StorageEncryption:
|
||||||
|
|
||||||
@attr.s(auto_attribs=True)
|
@attr.s(auto_attribs=True)
|
||||||
class SystemDetails:
|
class SystemDetails:
|
||||||
|
label: str
|
||||||
current: bool = False
|
current: bool = False
|
||||||
volumes: Dict[str, Volume] = attr.Factory(dict)
|
volumes: Dict[str, Volume] = attr.Factory(dict)
|
||||||
storage_encryption: Optional[StorageEncryption] = named_field(
|
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):
|
class SystemAction(enum.Enum):
|
||||||
INSTALL = "install"
|
INSTALL = "install"
|
||||||
|
|
||||||
|
@ -258,6 +264,9 @@ class SnapdAPI:
|
||||||
...
|
...
|
||||||
|
|
||||||
class systems:
|
class systems:
|
||||||
|
def GET() -> SystemsResponse:
|
||||||
|
...
|
||||||
|
|
||||||
@path_parameter
|
@path_parameter
|
||||||
class label:
|
class label:
|
||||||
def GET() -> SystemDetails:
|
def GET() -> SystemDetails:
|
||||||
|
|
Loading…
Reference in New Issue