diff --git a/examples/answers/bridge.yaml b/examples/answers/bridge.yaml new file mode 100644 index 000000000..1a0923f03 --- /dev/null +++ b/examples/answers/bridge.yaml @@ -0,0 +1,44 @@ +#source-catalog: examples/sources/bridge.yaml +Source: + source: ubuntu-server + search_drivers: true +Welcome: + lang: en_US +Refresh: + update: no +Keyboard: + layout: us +Zdev: + accept-default: yes +Network: + accept-default: yes +Proxy: + proxy: "" +Mirror: + country-code: us +Filesystem: + guided: yes + guided-index: 0 +Identity: + realname: Ubuntu + username: ubuntu + hostname: ubuntu-server + # ubuntu + password: '$6$wdAcoXrU039hKYPd$508Qvbe7ObUnxoj15DRCkzC3qO7edjH0VV7BPNRDYK4QR8ofJaEEF2heacn0QgD.f8pO8SNp83XNdWG6tocBM1' +SSH: + install_server: true + pwauth: false + authorized_keys: + - | + ssh-rsa AAAAAAAAAAAAAAAAAAAAAAAAA # ssh-import-id lp:subiquity +UbuntuPro: + token: "" +SnapList: + snaps: + hello: + channel: stable + classic: false +InstallProgress: + reboot: yes +Drivers: + install: no diff --git a/examples/sources/bridge.yaml b/examples/sources/bridge.yaml new file mode 100644 index 000000000..0adc4e6c7 --- /dev/null +++ b/examples/sources/bridge.yaml @@ -0,0 +1,28 @@ +version: 1 +sources: + - description: + en: This version has been customized to have a small runtime footprint in environments + where humans are not expected to log in. + id: ubuntu-server-minimal + locale_support: none + name: + en: Ubuntu Server (minimized) + path: ubuntu-server-minimal.squashfs + size: 530485248 + type: fsimage + variant: server + - default: true + description: + en: The default install contains a curated set of packages that provide a comfortable + experience for operating your server. + id: ubuntu-server + locale_support: locale-only + name: + en: Ubuntu Server + path: ubuntu-server-minimal.ubuntu-server.squashfs + size: 1066115072 + type: fsimage-layered + variant: server +bridge_kernel_name: linux-image-brg-22.04 +bridge_kernel_reasons: + - nvidia diff --git a/subiquity/models/source.py b/subiquity/models/source.py index 9382a2cf5..d15360bd0 100644 --- a/subiquity/models/source.py +++ b/subiquity/models/source.py @@ -13,6 +13,7 @@ # You should have received a copy of the GNU Affero General Public License # along with this program. If not, see . +import enum import logging import os import typing @@ -56,6 +57,19 @@ def __attrs_post_init__(self): ) +class BridgeReason(enum.Enum): + NVIDIA = "nvidia" + ZFS = "zfs" + + +@attr.s(auto_attribs=True, kw_only=True) +class SourceCatalog: + version: int + sources: typing.List[CatalogEntry] + bridge_kernel_name: typing.Optional[str] = None + bridge_kernel_reasons: typing.List[BridgeReason] = attr.Factory(list) + + legacy_server_entry = CatalogEntry( variant="server", id="synthesized", @@ -71,12 +85,14 @@ def __attrs_post_init__(self): }, ) +_serializer = Serializer(ignore_unknown_fields=True, serialize_enums_by="value") + class SourceModel: def __init__(self): self._dir = "/cdrom/casper" self.current = legacy_server_entry - self.sources = [self.current] + self.catalog = SourceCatalog(version=1, sources=[self.current]) self.lang = None self.search_drivers = False @@ -84,19 +100,24 @@ def load_from_file(self, fp): self._dir = os.path.dirname(fp.name) self.sources = [] self.current = None - self.sources = Serializer(ignore_unknown_fields=True).deserialize( - typing.List[CatalogEntry], yaml.safe_load(fp) - ) - for entry in self.sources: + content = yaml.safe_load(fp) + if isinstance(content, list): + self.catalog = SourceCatalog( + version=1, + sources=_serializer.deserialize(typing.List[CatalogEntry], content), + ) + else: + self.catalog = _serializer.deserialize(SourceCatalog, content) + for entry in self.catalog.sources: if entry.default: self.current = entry - log.debug("loaded %d sources from %r", len(self.sources), fp.name) + log.debug("loaded %d sources from %r", len(self.catalog.sources), fp.name) if self.current is None: - self.current = self.sources[0] + self.current = self.catalog.sources[0] def get_matching_source(self, id_: str) -> CatalogEntry: """Return a source object that has the ID requested.""" - for source in self.sources: + for source in self.catalog.sources: if source.id == id_: return source raise KeyError diff --git a/subiquity/server/controllers/source.py b/subiquity/server/controllers/source.py index 526ecc5b9..ee733c2ee 100644 --- a/subiquity/server/controllers/source.py +++ b/subiquity/server/controllers/source.py @@ -114,6 +114,8 @@ def start(self): self.app.hub.subscribe( (InstallerChannels.CONFIGURED, "locale"), self._set_locale ) + if self.model.catalog.version != 1: + raise Exception("unknown source catalog version") def _set_locale(self): current = self.app.base_model.locale.selected_language @@ -128,7 +130,7 @@ async def GET(self) -> SourceSelectionAndSetting: search_drivers = True return SourceSelectionAndSetting( - [convert_source(source, cur_lang) for source in self.model.sources], + [convert_source(source, cur_lang) for source in self.model.catalog.sources], self.model.current.id, search_drivers=search_drivers, )