source: add ability to select source in autoinstall
The source autoinstall section now supports the "id" field where the user can supply the ID of a source, e.g., "ubuntu-server" or "ubuntu-server-minimal". If the field is not supplied, the installation will use the source declared default: true (if any) in the source catalog. Otherwise, it the first source declared will be used. Signed-off-by: Olivier Gayot <olivier.gayot@canonical.com>
This commit is contained in:
parent
5378b5298c
commit
0c73bf9b86
|
@ -123,6 +123,9 @@
|
||||||
"properties": {
|
"properties": {
|
||||||
"search_drivers": {
|
"search_drivers": {
|
||||||
"type": "boolean"
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": [
|
"required": [
|
||||||
|
|
|
@ -13,6 +13,8 @@ late-commands:
|
||||||
- echo a
|
- echo a
|
||||||
keyboard:
|
keyboard:
|
||||||
layout: gb
|
layout: gb
|
||||||
|
source:
|
||||||
|
id: ubuntu-server-minimal
|
||||||
updates: security
|
updates: security
|
||||||
user-data:
|
user-data:
|
||||||
users:
|
users:
|
||||||
|
|
|
@ -225,8 +225,11 @@ LANG=C.UTF-8 timeout --foreground 60 \
|
||||||
--output-base "$tmpdir" \
|
--output-base "$tmpdir" \
|
||||||
--machine-config examples/simple.json \
|
--machine-config examples/simple.json \
|
||||||
--autoinstall examples/autoinstall-user-data.yaml \
|
--autoinstall examples/autoinstall-user-data.yaml \
|
||||||
--kernel-cmdline autoinstall
|
--kernel-cmdline autoinstall \
|
||||||
|
--source-catalog examples/install-sources.yaml
|
||||||
validate
|
validate
|
||||||
|
python3 scripts/check-yaml-fields.py "$tmpdir"/var/log/installer/autoinstall-user-data \
|
||||||
|
'autoinstall.source.id="ubuntu-server-minimal"'
|
||||||
grep -q 'finish: subiquity/Install/install/postinstall/run_unattended_upgrades: SUCCESS: downloading and installing security updates' $tmpdir/subiquity-server-debug.log
|
grep -q 'finish: subiquity/Install/install/postinstall/run_unattended_upgrades: SUCCESS: downloading and installing security updates' $tmpdir/subiquity-server-debug.log
|
||||||
|
|
||||||
# The OOBE doesn't exist in WSL < 20.04
|
# The OOBE doesn't exist in WSL < 20.04
|
||||||
|
|
|
@ -88,6 +88,13 @@ class SourceModel:
|
||||||
if self.current is None:
|
if self.current is None:
|
||||||
self.current = self.sources[0]
|
self.current = self.sources[0]
|
||||||
|
|
||||||
|
def get_matching_source(self, id_: str) -> CatalogEntry:
|
||||||
|
""" Return a source object that has the ID requested. """
|
||||||
|
for source in self.sources:
|
||||||
|
if source.id == id_:
|
||||||
|
return source
|
||||||
|
raise KeyError
|
||||||
|
|
||||||
def get_source(self):
|
def get_source(self):
|
||||||
path = os.path.join(self._dir, self.current.path)
|
path = os.path.join(self._dir, self.current.path)
|
||||||
if self.current.preinstalled_langs:
|
if self.current.preinstalled_langs:
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# You should have received a copy of the GNU Affero General Public License
|
# 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/>.
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import contextlib
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
@ -59,6 +60,9 @@ class SourceController(SubiquityController):
|
||||||
"search_drivers": {
|
"search_drivers": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
},
|
},
|
||||||
|
"id": {
|
||||||
|
"type": "string",
|
||||||
|
},
|
||||||
},
|
},
|
||||||
"required": ["search_drivers"],
|
"required": ["search_drivers"],
|
||||||
}
|
}
|
||||||
|
@ -71,15 +75,19 @@ class SourceController(SubiquityController):
|
||||||
super().__init__(app)
|
super().__init__(app)
|
||||||
self._handler = None
|
self._handler = None
|
||||||
self.source_path: Optional[str] = None
|
self.source_path: Optional[str] = None
|
||||||
|
self.ai_source_id: Optional[str] = None
|
||||||
|
|
||||||
def make_autoinstall(self):
|
def make_autoinstall(self):
|
||||||
return {"search_drivers": self.model.search_drivers}
|
return {
|
||||||
|
"search_drivers": self.model.search_drivers,
|
||||||
|
"id": self.model.current.id,
|
||||||
|
}
|
||||||
|
|
||||||
def load_autoinstall_data(self, data: Any) -> None:
|
def load_autoinstall_data(self, data: Any) -> None:
|
||||||
if data is None:
|
if data is None:
|
||||||
# For some reason, the schema validator does not reject
|
# For some reason, the schema validator does not reject
|
||||||
# "source: null" despite "type" being "object"
|
# "source: null" despite "type" being "object"
|
||||||
data = self.autoinstall_default
|
data = {**self.autoinstall_default, "id": None}
|
||||||
|
|
||||||
# search_drivers is marked required so the schema validator should
|
# search_drivers is marked required so the schema validator should
|
||||||
# reject any missing data.
|
# reject any missing data.
|
||||||
|
@ -87,6 +95,15 @@ class SourceController(SubiquityController):
|
||||||
|
|
||||||
self.model.search_drivers = data["search_drivers"]
|
self.model.search_drivers = data["search_drivers"]
|
||||||
|
|
||||||
|
# At this point, the model has not yet loaded the sources from the
|
||||||
|
# catalog. So we store the data and lean on apply_autoinstall_config.
|
||||||
|
self.ai_source_id = data.get("id")
|
||||||
|
|
||||||
|
async def apply_autoinstall_config(self) -> None:
|
||||||
|
if self.ai_source_id is None:
|
||||||
|
return
|
||||||
|
self.model.current = self.model.get_matching_source(self.ai_source_id)
|
||||||
|
|
||||||
def start(self):
|
def start(self):
|
||||||
path = '/cdrom/casper/install-sources.yaml'
|
path = '/cdrom/casper/install-sources.yaml'
|
||||||
if self.app.opts.source_catalog is not None:
|
if self.app.opts.source_catalog is not None:
|
||||||
|
@ -129,7 +146,6 @@ class SourceController(SubiquityController):
|
||||||
async def POST(self, source_id: str,
|
async def POST(self, source_id: str,
|
||||||
search_drivers: bool = False) -> None:
|
search_drivers: bool = False) -> None:
|
||||||
self.model.search_drivers = search_drivers
|
self.model.search_drivers = search_drivers
|
||||||
for source in self.model.sources:
|
with contextlib.suppress(KeyError):
|
||||||
if source.id == source_id:
|
self.model.current = self.model.get_matching_source(source_id)
|
||||||
self.model.current = source
|
|
||||||
await self.configured()
|
await self.configured()
|
||||||
|
|
Loading…
Reference in New Issue