diff --git a/autoinstall-schema.json b/autoinstall-schema.json
index 05b21120..cb6c4976 100644
--- a/autoinstall-schema.json
+++ b/autoinstall-schema.json
@@ -420,6 +420,14 @@
"additionalProperties": false
}
},
+ "codecs": {
+ "type": "object",
+ "properties": {
+ "install": {
+ "type": "boolean"
+ }
+ }
+ },
"drivers": {
"type": "object",
"properties": {
diff --git a/documentation/autoinstall-reference.md b/documentation/autoinstall-reference.md
index 28cd4823..015b8065 100644
--- a/documentation/autoinstall-reference.md
+++ b/documentation/autoinstall-reference.md
@@ -411,6 +411,23 @@ A list of SSH public keys to install in the initial user's account.
**type:** boolean
**default:** `true` if `authorized_keys` is empty, `false` otherwise
+
+
+### codecs
+
+**type:** mapping, see below
+**default:** see below
+**can be interactive:** no
+
+Configure whether common restricted packages (including codecs) from [multiverse] should be installed.
+
+#### install
+
+**type:** boolean
+**default:** `false`
+
+Whether to install the ubuntu-restricted-addons package.
+
### drivers
diff --git a/documentation/autoinstall-schema.md b/documentation/autoinstall-schema.md
index 0b43f25f..6ba66742 100644
--- a/documentation/autoinstall-schema.md
+++ b/documentation/autoinstall-schema.md
@@ -442,6 +442,14 @@ The [JSON schema](https://json-schema.org/) for autoinstall data is as follows:
"additionalProperties": false
}
},
+ "codecs": {
+ "type": "object",
+ "properties": {
+ "install": {
+ "type": "boolean"
+ }
+ }
+ },
"drivers": {
"type": "object",
"properties": {
diff --git a/subiquity/common/apidef.py b/subiquity/common/apidef.py
index 0ce0808d..8523104b 100644
--- a/subiquity/common/apidef.py
+++ b/subiquity/common/apidef.py
@@ -44,6 +44,7 @@ from subiquity.common.types import (
ReformatDisk,
RefreshStatus,
ShutdownMode,
+ CodecsData,
DriversResponse,
DriversPayload,
SnapInfo,
@@ -316,6 +317,10 @@ class API:
def POST(data: Payload[ModifyPartitionV2]) \
-> StorageResponseV2: ...
+ class codecs:
+ def GET() -> CodecsData: ...
+ def POST(data: Payload[CodecsData]) -> None: ...
+
class drivers:
def GET(wait: bool = False) -> DriversResponse: ...
def POST(data: Payload[DriversPayload]) -> None: ...
diff --git a/subiquity/common/types.py b/subiquity/common/types.py
index f2243232..54554b46 100644
--- a/subiquity/common/types.py
+++ b/subiquity/common/types.py
@@ -542,6 +542,11 @@ class DriversResponse:
search_drivers: bool
+@attr.s(auto_attribs=True)
+class CodecsData:
+ install: bool
+
+
@attr.s(auto_attribs=True)
class DriversPayload:
install: bool
diff --git a/subiquity/models/codecs.py b/subiquity/models/codecs.py
new file mode 100644
index 00000000..2f4f4b42
--- /dev/null
+++ b/subiquity/models/codecs.py
@@ -0,0 +1,29 @@
+# Copyright 2022 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 .
+
+import logging
+
+log = logging.getLogger('subiquity.models.codecs')
+
+
+class CodecsModel:
+ do_install = False
+
+ async def target_packages(self):
+ # NOTE currently, ubuntu-restricted-addons is an empty package that
+ # pulls relevant packages through Recommends: Ideally, we should make
+ # sure to run the APT command for this package with the
+ # --install-recommends option.
+ return ["ubuntu-restricted-addons"] if self.do_install else []
diff --git a/subiquity/models/subiquity.py b/subiquity/models/subiquity.py
index 75e9ae9b..bd0dccb6 100644
--- a/subiquity/models/subiquity.py
+++ b/subiquity/models/subiquity.py
@@ -46,6 +46,7 @@ from subiquitycore.lsb_release import lsb_release
from subiquity.common.resources import get_users_and_groups
from subiquity.server.types import InstallerChannels
+from .codecs import CodecsModel
from .drivers import DriversModel
from .filesystem import FilesystemModel
from .identity import IdentityModel
@@ -173,6 +174,7 @@ class SubiquityModel:
self.target = root
self.chroot_prefix = []
+ self.codecs = CodecsModel()
self.debconf_selections = DebconfSelectionsModel()
self.drivers = DriversModel()
self.filesystem = FilesystemModel()
diff --git a/subiquity/server/controllers/__init__.py b/subiquity/server/controllers/__init__.py
index a4038f6c..a609a4f1 100644
--- a/subiquity/server/controllers/__init__.py
+++ b/subiquity/server/controllers/__init__.py
@@ -14,6 +14,7 @@
# along with this program. If not, see .
from .cmdlist import EarlyController, LateController, ErrorController
+from .codecs import CodecsController
from .debconf import DebconfController
from .drivers import DriversController
from .filesystem import FilesystemController
@@ -39,6 +40,7 @@ from .userdata import UserdataController
from .zdev import ZdevController
__all__ = [
+ 'CodecsController',
'DebconfController',
'DriversController',
'EarlyController',
diff --git a/subiquity/server/controllers/codecs.py b/subiquity/server/controllers/codecs.py
new file mode 100644
index 00000000..312b1078
--- /dev/null
+++ b/subiquity/server/controllers/codecs.py
@@ -0,0 +1,62 @@
+# Copyright 2022 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 .
+
+import logging
+
+from subiquity.common.apidef import API
+from subiquity.common.types import CodecsData
+from subiquity.server.controller import SubiquityController
+
+log = logging.getLogger('subiquity.server.controllers.codecs')
+
+
+class CodecsController(SubiquityController):
+
+ endpoint = API.codecs
+
+ autoinstall_key = model_name = "codecs"
+ autoinstall_schema = {
+ 'type': 'object',
+ 'properties': {
+ 'install': {
+ 'type': 'boolean',
+ },
+ },
+ }
+ autoinstall_default = {"install": False}
+
+ def serialize(self):
+ return self.model.do_install
+
+ def deserialize(self, data):
+ if data is None:
+ return
+ self.model.do_install = data
+
+ def make_autoinstall(self):
+ return {
+ "install": self.model.do_install,
+ }
+
+ def load_autoinstall_data(self, data):
+ if data is not None and "install" in data:
+ self.model.do_install = data["install"]
+
+ async def GET(self) -> CodecsData:
+ return CodecsData(install=self.model.do_install)
+
+ async def POST(self, data: CodecsData) -> None:
+ self.model.do_install = data.install
+ await self.configured()
diff --git a/subiquity/server/server.py b/subiquity/server/server.py
index 85abd580..6c50b0f9 100644
--- a/subiquity/server/server.py
+++ b/subiquity/server/server.py
@@ -217,7 +217,7 @@ POSTINSTALL_MODEL_NAMES = ModelNames({
"ubuntu_pro",
"userdata",
},
- desktop={"timezone"})
+ desktop={"timezone", "codecs"})
class SubiquityServer(Application):
@@ -260,6 +260,7 @@ class SubiquityServer(Application):
"Identity",
"SSH",
"SnapList",
+ "Codecs",
"Drivers",
"TimeZone",
"Install",