From e32b7f28ac3d4abc1f4cd77c913ad77a38599980 Mon Sep 17 00:00:00 2001 From: Dan Bungert Date: Wed, 4 Aug 2021 14:27:32 -0600 Subject: [PATCH] mirror: add disable_components API --- autoinstall-schema.json | 13 +++++++ subiquity/common/apidef.py | 9 ++++- subiquity/models/mirror.py | 6 +++ subiquity/models/tests/test_mirror.py | 10 +++++ subiquity/server/apt.py | 2 +- subiquity/server/controllers/mirror.py | 17 ++++++++- .../server/controllers/tests/test_mirror.py | 38 +++++++++++++++++++ 7 files changed, 92 insertions(+), 3 deletions(-) create mode 100644 subiquity/server/controllers/tests/test_mirror.py diff --git a/autoinstall-schema.json b/autoinstall-schema.json index 31f22696..5e27b33b 100644 --- a/autoinstall-schema.json +++ b/autoinstall-schema.json @@ -281,6 +281,19 @@ }, "sources": { "type": "object" + }, + "disable_components": { + "type": "array", + "items": { + "type": "string", + "enum": [ + "universe", + "multiverse", + "restricted", + "contrib", + "non-free" + ] + } } } }, diff --git a/subiquity/common/apidef.py b/subiquity/common/apidef.py index de9c932c..aa538876 100644 --- a/subiquity/common/apidef.py +++ b/subiquity/common/apidef.py @@ -60,7 +60,6 @@ class API: """The API offered by the subiquity installer process.""" identity = simple_endpoint(IdentityData) locale = simple_endpoint(str) - mirror = simple_endpoint(str) proxy = simple_endpoint(str) ssh = simple_endpoint(SSHData) updates = simple_endpoint(str) @@ -297,6 +296,14 @@ class API: class shutdown: def POST(mode: ShutdownMode, immediate: bool = False): ... + class mirror: + def GET() -> str: ... + def POST(data: Payload[str]): ... + + class disable_components: + def GET() -> List[str]: ... + def POST(data: Payload[List[str]]): ... + class LinkAction(enum.Enum): NEW = enum.auto() diff --git a/subiquity/models/mirror.py b/subiquity/models/mirror.py index 31931ea8..af57cb5c 100644 --- a/subiquity/models/mirror.py +++ b/subiquity/models/mirror.py @@ -51,6 +51,12 @@ class MirrorModel(object): self.config = copy.deepcopy(DEFAULT) self.architecture = get_architecture() self.default_mirror = self.get_mirror() + self.disable_components = set() + + def get_config(self): + config = copy.deepcopy(self.config) + config['disable_components'] = list(self.disable_components) + return config def mirror_is_default(self): return self.get_mirror() == self.default_mirror diff --git a/subiquity/models/tests/test_mirror.py b/subiquity/models/tests/test_mirror.py index 8a5bf424..1a23087f 100644 --- a/subiquity/models/tests/test_mirror.py +++ b/subiquity/models/tests/test_mirror.py @@ -42,3 +42,13 @@ class TestMirrorModel(unittest.TestCase): model.set_mirror("http://mymirror.invalid/") model.set_country("CC") self.assertEqual(model.get_mirror(), "http://mymirror.invalid/") + + def test_default_disable_components(self): + config = MirrorModel().get_config() + self.assertEqual([], config['disable_components']) + + def test_set_disable_components(self): + model = MirrorModel() + model.disable_components = set(['universe']) + config = model.get_config() + self.assertEqual(['universe'], config['disable_components']) diff --git a/subiquity/server/apt.py b/subiquity/server/apt.py index 2f9536aa..bf520c10 100644 --- a/subiquity/server/apt.py +++ b/subiquity/server/apt.py @@ -104,7 +104,7 @@ class AptConfigurer: config_upper = await self.setup_overlay(self.source, self.configured) config = { - 'apt': self.app.base_model.mirror.config, + 'apt': self.app.base_model.mirror.get_config(), } config_location = os.path.join( self.app.root, 'var/log/installer/subiquity-curtin-apt.conf') diff --git a/subiquity/server/controllers/mirror.py b/subiquity/server/controllers/mirror.py index 67afdfe6..e623ba4c 100644 --- a/subiquity/server/controllers/mirror.py +++ b/subiquity/server/controllers/mirror.py @@ -16,6 +16,7 @@ import asyncio import copy import logging +from typing import List from curtin.config import merge_config @@ -40,8 +41,16 @@ class MirrorController(SubiquityController): 'primary': {'type': 'array'}, 'geoip': {'type': 'boolean'}, 'sources': {'type': 'object'}, - }, + 'disable_components': { + 'type': 'array', + 'items': { + 'type': 'string', + 'enum': ['universe', 'multiverse', 'restricted', + 'contrib', 'non-free'] + } + } } + } model_name = "mirror" def __init__(self, app): @@ -89,3 +98,9 @@ class MirrorController(SubiquityController): async def POST(self, data: str): self.model.set_mirror(data) await self.configured() + + async def disable_components_GET(self) -> List[str]: + return list(self.model.disable_components) + + async def disable_components_POST(self, data: List[str]): + self.model.disable_components = set(data) diff --git a/subiquity/server/controllers/tests/test_mirror.py b/subiquity/server/controllers/tests/test_mirror.py new file mode 100644 index 00000000..475315a5 --- /dev/null +++ b/subiquity/server/controllers/tests/test_mirror.py @@ -0,0 +1,38 @@ +# Copyright 2021 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 jsonschema +import unittest + +from subiquity.server.controllers.mirror import MirrorController + + +class TestMirrorSchema(unittest.TestCase): + def validate(self, data): + jsonschema.validate(data, MirrorController.autoinstall_schema) + + def test_empty(self): + self.validate({}) + + def test_disable_components(self): + self.validate({'disable_components': ['universe']}) + + def test_no_disable_main(self): + with self.assertRaises(jsonschema.ValidationError): + self.validate({'disable_components': ['main']}) + + def test_no_disable_random_junk(self): + with self.assertRaises(jsonschema.ValidationError): + self.validate({'disable_components': ['not-a-component']})