Skip to content

Commit

Permalink
Merge pull request #2140 from dbungert/component-step3-dash-to-unders…
Browse files Browse the repository at this point in the history
…core

a nicer way to handle _ vs - in field names in snapd api
  • Loading branch information
dbungert authored Jan 21, 2025
2 parents 88e8fc7 + 9702b68 commit 875843c
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 36 deletions.
2 changes: 1 addition & 1 deletion subiquity/server/controllers/filesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -922,7 +922,7 @@ async def guided_core_boot(self, disk: Disk):
part.wipe = "superblock"
self.delete_filesystem(part.fs())
fs = self.model.add_filesystem(
part, structure.filesystem, label=structure.label
part, structure.filesystem, label=structure.filesystem_label
)
if structure.role == snapdtypes.Role.SYSTEM_DATA:
self.model.add_mount(fs, "/")
Expand Down
40 changes: 40 additions & 0 deletions subiquity/server/snapd/test/test_types.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
# Copyright 2025 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from unittest import TestCase

import attr
import attrs

from subiquity.server.snapd.types import snapdtype
from subiquitycore.tests.parameterized import parameterized


class TestMetadataMerge(TestCase):
@parameterized.expand(
(
# non-name metadata should be merged in
({"stuff": "things"}, {"stuff": "things", "name": "foo-bar"}),
# a conflict on the metadata field name is overwritten
({"name": "foobar"}, {"name": "foo-bar"}),
)
)
def test_merge(self, initial, expected):
@snapdtype
class MetadataMerge:
foo_bar: int = attr.ib(metadata=initial)

[field] = attrs.fields(MetadataMerge)
self.assertEqual(expected, field.metadata)
78 changes: 43 additions & 35 deletions subiquity/server/snapd/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,33 @@ def date_field(name=None, default=attr.NOTHING):
ChangeID = str


def _underscore_to_hyphen(cls, fields):
results = []
for field in fields:
metadata = field.metadata | {"name": field.name.replace("_", "-")}
results.append(field.evolve(metadata=metadata))
return results


def snapdtype(cls):
return attr.s(
auto_attribs=True, kw_only=True, field_transformer=_underscore_to_hyphen
)(cls)


class SnapStatus(enum.Enum):
ACTIVE = "active"
AVAILABLE = "available"


@attr.s(auto_attribs=True)
@snapdtype
class Publisher:
id: str
username: str
display_name: str = named_field("display-name")
display_name: str


@attr.s(auto_attribs=True)
@snapdtype
class Snap:
id: str
name: str
Expand All @@ -61,11 +75,11 @@ class SnapAction(enum.Enum):
SWITCH = "switch"


@attr.s(auto_attribs=True)
@snapdtype
class SnapActionRequest:
action: SnapAction
channel: str = ""
ignore_running: bool = named_field("ignore-running", False)
ignore_running: bool = False


class ResponseType:
Expand All @@ -74,10 +88,10 @@ class ResponseType:
ERROR = "error"


@attr.s(auto_attribs=True)
@snapdtype
class Response:
type: str
status_code: int = named_field("status-code")
status_code: int
status: str


Expand All @@ -88,35 +102,35 @@ class Role(enum.Enum):
SYSTEM_DATA = "system-data"


@attr.s(auto_attribs=True)
@snapdtype
class RelativeOffset:
relative_to: str = named_field("relative-to")
relative_to: str
offset: int


@attr.s(auto_attribs=True)
@snapdtype
class VolumeContent:
source: str = ""
target: str = ""
image: str = ""
offset: Optional[int] = None
offset_write: Optional[RelativeOffset] = named_field("offset-write", None)
offset_write: Optional[RelativeOffset] = None
size: int = 0
unpack: bool = False


@attr.s(auto_attribs=True)
@snapdtype
class VolumeUpdate:
edition: int = 0
preserve: Optional[List[str]] = None


@attr.s(auto_attribs=True)
@snapdtype
class VolumeStructure:
name: str = ""
label: str = named_field("filesystem-label", "")
filesystem_label: str = ""
offset: Optional[int] = None
offset_write: Optional[RelativeOffset] = named_field("offset-write", None)
offset_write: Optional[RelativeOffset] = None
size: int = 0
type: str = ""
role: NonExhaustive[Role] = Role.NONE
Expand All @@ -132,15 +146,15 @@ def gpt_part_type_uuid(self):
return self.type


@attr.s(auto_attribs=True)
@snapdtype
class Volume:
schema: str = ""
bootloader: str = ""
id: str = ""
structure: Optional[List[VolumeStructure]] = None


@attr.s(auto_attribs=True)
@snapdtype
class OnVolumeStructure(VolumeStructure):
device: Optional[str] = None

Expand All @@ -149,7 +163,7 @@ def from_volume_structure(cls, vs: VolumeStructure):
return cls(**attr.asdict(vs, recurse=False))


@attr.s(auto_attribs=True)
@snapdtype
class OnVolume(Volume):
structure: Optional[List[OnVolumeStructure]] = None

Expand Down Expand Up @@ -182,27 +196,23 @@ class EncryptionType(enum.Enum):
DEVICE_SETUP_HOOK = "device-setup-hook"


@attr.s(auto_attribs=True)
@snapdtype
class StorageEncryption:
support: StorageEncryptionSupport
storage_safety: StorageSafety = named_field("storage-safety")
encryption_type: EncryptionType = named_field(
"encryption-type", default=EncryptionType.NONE
)
unavailable_reason: str = named_field("unavailable-reason", default="")
storage_safety: StorageSafety
encryption_type: EncryptionType = EncryptionType.NONE
unavailable_reason: str = ""


@attr.s(auto_attribs=True)
@snapdtype
class SystemDetails:
label: str
current: bool = False
volumes: Dict[str, Volume] = attr.Factory(dict)
storage_encryption: Optional[StorageEncryption] = named_field(
"storage-encryption", default=None
)
storage_encryption: Optional[StorageEncryption] = None


@attr.s(auto_attribs=True)
@snapdtype
class SystemsResponse:
systems: List[SystemDetails] = attr.Factory(list)

Expand All @@ -216,15 +226,13 @@ class SystemActionStep(enum.Enum):
FINISH = "finish"


@attr.s(auto_attribs=True)
@snapdtype
class SystemActionRequest:
action: SystemAction
step: SystemActionStep
on_volumes: Dict[str, OnVolume] = named_field("on-volumes")
on_volumes: Dict[str, OnVolume]


@attr.s(auto_attribs=True)
@snapdtype
class SystemActionResponse:
encrypted_devices: Dict[NonExhaustive[Role], str] = named_field(
"encrypted-devices", default=attr.Factory(dict)
)
encrypted_devices: Dict[NonExhaustive[Role], str] = attr.Factory(dict)

0 comments on commit 875843c

Please sign in to comment.