Merge pull request #1897 from Chris-Peterson444/autoinstall-exception-FR-6293
AutoinstallError exception
This commit is contained in:
commit
48e5f9c616
|
@ -6,6 +6,12 @@
|
|||
"minimum": 1,
|
||||
"maximum": 1
|
||||
},
|
||||
"interactive-sections": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"early-commands": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
|
@ -6,6 +6,12 @@
|
|||
"minimum": 1,
|
||||
"maximum": 1
|
||||
},
|
||||
"interactive-sections": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"early-commands": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
import logging
|
||||
|
||||
log = logging.getLogger("subiquity.server.autoinstall")
|
||||
|
||||
|
||||
class AutoinstallError(Exception):
|
||||
pass
|
||||
|
||||
|
||||
class AutoinstallValidationError(AutoinstallError):
|
||||
def __init__(
|
||||
self,
|
||||
owner: str,
|
||||
):
|
||||
self.message = f"Malformed autoinstall in {owner!r} section"
|
||||
self.owner = owner
|
||||
super().__init__(self.message)
|
|
@ -19,8 +19,10 @@ import os
|
|||
from typing import Any, Optional
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.exceptions import ValidationError
|
||||
|
||||
from subiquity.common.api.server import bind
|
||||
from subiquity.server.autoinstall import AutoinstallValidationError
|
||||
from subiquity.server.types import InstallerChannels
|
||||
from subiquitycore.context import with_context
|
||||
from subiquitycore.controller import BaseController
|
||||
|
@ -54,6 +56,19 @@ class SubiquityController(BaseController):
|
|||
await self.configured()
|
||||
self._active = False
|
||||
|
||||
def validate_autoinstall(self, ai_data: dict) -> None:
|
||||
try:
|
||||
jsonschema.validate(ai_data, self.autoinstall_schema)
|
||||
|
||||
except ValidationError as original_exception:
|
||||
section = self.autoinstall_key
|
||||
|
||||
new_exception: AutoinstallValidationError = AutoinstallValidationError(
|
||||
section,
|
||||
)
|
||||
|
||||
raise new_exception from original_exception
|
||||
|
||||
def setup_autoinstall(self):
|
||||
if not self.app.autoinstall_config:
|
||||
return
|
||||
|
@ -72,7 +87,8 @@ class SubiquityController(BaseController):
|
|||
ai_data = self.autoinstall_default
|
||||
|
||||
if ai_data is not None and self.autoinstall_schema is not None:
|
||||
jsonschema.validate(ai_data, self.autoinstall_schema)
|
||||
self.validate_autoinstall(ai_data)
|
||||
|
||||
self.load_autoinstall_data(ai_data)
|
||||
|
||||
def load_autoinstall_data(self, data):
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.cmdlist import CmdListController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestCmdListController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
CmdListController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(CmdListController.autoinstall_schema)
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.codecs import CodecsController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestCodecsController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
CodecsController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(CodecsController.autoinstall_schema)
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.debconf import DebconfController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestDebconfController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
DebconfController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(DebconfController.autoinstall_schema)
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.drivers import DriversController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestDriversController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
DriversController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(DriversController.autoinstall_schema)
|
|
@ -18,7 +18,9 @@ import subprocess
|
|||
import uuid
|
||||
from unittest import IsolatedAsyncioTestCase, mock
|
||||
|
||||
import jsonschema
|
||||
from curtin.commands.extract import TrivialSourceHandler
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.common.filesystem import gaps, labels
|
||||
from subiquity.common.filesystem.actions import DeviceAction
|
||||
|
@ -399,6 +401,15 @@ class TestSubiquityControllerFilesystem(IsolatedAsyncioTestCase):
|
|||
self.assertEqual(len(self.fsc._variation_info), 1)
|
||||
self.assertEqual(self.fsc._variation_info["default"].name, "default")
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
FilesystemController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(FilesystemController.autoinstall_schema)
|
||||
|
||||
|
||||
class TestGuided(IsolatedAsyncioTestCase):
|
||||
boot_expectations = [
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.identity import IdentityController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestIdentityController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
IdentityController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(IdentityController.autoinstall_schema)
|
|
@ -17,6 +17,9 @@ import os
|
|||
import unittest
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.common.types import KeyboardSetting
|
||||
from subiquity.models.keyboard import KeyboardModel
|
||||
from subiquity.server.controllers.keyboard import KeyboardController
|
||||
|
@ -29,6 +32,16 @@ class opts:
|
|||
dry_run = True
|
||||
|
||||
|
||||
class TestKeyboardController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
KeyboardController.autoinstall_schema
|
||||
)
|
||||
JsonValidator.check_schema(KeyboardController.autoinstall_schema)
|
||||
|
||||
|
||||
class TestSubiquityModel(SubiTestCase):
|
||||
async def test_write_config(self):
|
||||
os.environ["SUBIQUITY_REPLAY_TIMESCALE"] = "100"
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.locale import LocaleController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestLocaleController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
LocaleController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(LocaleController.autoinstall_schema)
|
|
@ -19,6 +19,7 @@ import unittest
|
|||
from unittest import mock
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.common.types import MirrorSelectionFallback
|
||||
from subiquity.models.mirror import MirrorModel
|
||||
|
@ -264,3 +265,12 @@ class TestMirrorController(unittest.IsolatedAsyncioTestCase):
|
|||
mock_fallback.assert_not_called()
|
||||
await controller.run_mirror_selection_or_fallback(context=None)
|
||||
mock_fallback.assert_called_once()
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
MirrorController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(MirrorController.autoinstall_schema)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.network import NetworkController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestNetworkController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
NetworkController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(NetworkController.autoinstall_schema)
|
|
@ -16,6 +16,9 @@
|
|||
import subprocess
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.oem import OEMController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
from subiquitycore.tests.mocks import make_app
|
||||
|
@ -110,3 +113,12 @@ Ubuntu-Oem-Kernel-Flavour: oem
|
|||
"oem-sutton-balint-meta", context=None, overlay=Mock()
|
||||
)
|
||||
)
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
OEMController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(OEMController.autoinstall_schema)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.package import PackageController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestPackageController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
PackageController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(PackageController.autoinstall_schema)
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.proxy import ProxyController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestProxyController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
ProxyController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(ProxyController.autoinstall_schema)
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
from unittest import mock
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server import snapdapi
|
||||
from subiquity.server.controllers import refresh as refresh_mod
|
||||
from subiquity.server.controllers.refresh import RefreshController, SnapChannelSource
|
||||
|
@ -99,3 +102,12 @@ class TestRefreshController(SubiTestCase):
|
|||
await self.rc.configure_snapd(context=self.rc.context)
|
||||
|
||||
paw.assert_not_called()
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
RefreshController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(RefreshController.autoinstall_schema)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.reporting import ReportingController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestReportingController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
ReportingController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(ReportingController.autoinstall_schema)
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.shutdown import ShutdownController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestShutdownController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
ShutdownController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(ShutdownController.autoinstall_schema)
|
|
@ -16,13 +16,17 @@
|
|||
import unittest
|
||||
from unittest.mock import AsyncMock
|
||||
|
||||
import jsonschema
|
||||
import requests
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.models.snaplist import SnapListModel
|
||||
from subiquity.server.controllers.snaplist import (
|
||||
SnapdSnapInfoLoader,
|
||||
SnapListController,
|
||||
SnapListFetchError,
|
||||
)
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
from subiquitycore.tests.mocks import make_app
|
||||
|
||||
|
||||
|
@ -56,3 +60,14 @@ class TestSnapdSnapInfoLoader(unittest.IsolatedAsyncioTestCase):
|
|||
await self.loader.get_snap_list_task()
|
||||
self.assertTrue(self.loader.fetch_list_completed())
|
||||
self.assertFalse(self.loader.fetch_list_failed())
|
||||
|
||||
|
||||
class TestSnapListController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
SnapListController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(SnapListController.autoinstall_schema)
|
||||
|
|
|
@ -16,6 +16,9 @@
|
|||
import unittest
|
||||
from unittest import mock
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.common.types import SSHFetchIdStatus, SSHIdentity
|
||||
from subiquity.server.controllers.ssh import (
|
||||
SSHController,
|
||||
|
@ -116,3 +119,12 @@ class TestSSHController(unittest.IsolatedAsyncioTestCase):
|
|||
self.assertEqual(response.status, SSHFetchIdStatus.FINGERPRINT_ERROR)
|
||||
self.assertEqual(response.error, stderr)
|
||||
self.assertIsNone(response.identities)
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
SSHController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(SSHController.autoinstall_schema)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.timezone import TimeZoneController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestTimeZoneController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
TimeZoneController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(TimeZoneController.autoinstall_schema)
|
|
@ -15,6 +15,9 @@
|
|||
|
||||
import unittest
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.ubuntu_pro import UbuntuProController
|
||||
from subiquity.server.dryrun import DRConfig
|
||||
from subiquitycore.tests.mocks import make_app
|
||||
|
@ -33,3 +36,12 @@ class TestUbuntuProController(unittest.TestCase):
|
|||
def test_deserialize(self):
|
||||
self.controller.deserialize("1A2B3C4D")
|
||||
self.assertEqual(self.controller.model.token, "1A2B3C4D")
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
UbuntuProController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(UbuntuProController.autoinstall_schema)
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
# Copyright 2024 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/>.
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.updates import UpdatesController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
|
||||
|
||||
class TestUpdatesController(SubiTestCase):
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
UpdatesController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(UpdatesController.autoinstall_schema)
|
|
@ -15,7 +15,9 @@
|
|||
|
||||
import unittest
|
||||
|
||||
import jsonschema
|
||||
from cloudinit.config.schema import SchemaValidationError
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.server.controllers.userdata import UserdataController
|
||||
from subiquitycore.tests.mocks import make_app
|
||||
|
@ -58,3 +60,12 @@ class TestUserdataController(unittest.TestCase):
|
|||
validate.assert_called_with(
|
||||
data=invalid_schema, data_source="autoinstall.user-data"
|
||||
)
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
UserdataController.autoinstall_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(UserdataController.autoinstall_schema)
|
||||
|
|
|
@ -24,12 +24,13 @@ import jsonschema
|
|||
import yaml
|
||||
from aiohttp import web
|
||||
from cloudinit.config.cc_set_passwords import rand_user_password
|
||||
from jsonschema.exceptions import ValidationError
|
||||
from systemd import journal
|
||||
|
||||
from subiquity.cloudinit import get_host_combined_cloud_config
|
||||
from subiquity.common.api.server import bind, controller_for_request
|
||||
from subiquity.common.apidef import API
|
||||
from subiquity.common.errorreport import ErrorReporter, ErrorReportKind
|
||||
from subiquity.common.errorreport import ErrorReport, ErrorReporter, ErrorReportKind
|
||||
from subiquity.common.serialize import to_json
|
||||
from subiquity.common.types import (
|
||||
ApplicationState,
|
||||
|
@ -40,6 +41,7 @@ from subiquity.common.types import (
|
|||
PasswordKind,
|
||||
)
|
||||
from subiquity.models.subiquity import ModelNames, SubiquityModel
|
||||
from subiquity.server.autoinstall import AutoinstallError, AutoinstallValidationError
|
||||
from subiquity.server.controller import SubiquityController
|
||||
from subiquity.server.dryrun import DRConfig
|
||||
from subiquity.server.errors import ErrorController
|
||||
|
@ -222,6 +224,12 @@ class SubiquityServer(Application):
|
|||
"minimum": 1,
|
||||
"maximum": 1,
|
||||
},
|
||||
"interactive-sections": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
},
|
||||
},
|
||||
},
|
||||
"required": ["version"],
|
||||
"additionalProperties": True,
|
||||
|
@ -395,7 +403,8 @@ class SubiquityServer(Application):
|
|||
def make_apport_report(self, kind, thing, *, wait=False, **kw):
|
||||
return self.error_reporter.make_apport_report(kind, thing, wait=wait, **kw)
|
||||
|
||||
async def _run_error_cmds(self, report):
|
||||
async def _run_error_cmds(self, report: Optional[ErrorReport] = None) -> None:
|
||||
if report is not None and report._info_task is not None:
|
||||
await report._info_task
|
||||
Error = getattr(self.controllers, "Error", None)
|
||||
if Error is not None and Error.cmds:
|
||||
|
@ -413,7 +422,7 @@ class SubiquityServer(Application):
|
|||
return
|
||||
report = self.error_reporter.report_for_exc(exc)
|
||||
log.error("top level error", exc_info=exc)
|
||||
if not report:
|
||||
if not isinstance(exc, AutoinstallError) and not report:
|
||||
report = self.make_apport_report(
|
||||
ErrorReportKind.UNKNOWN, "unknown error", exc=exc
|
||||
)
|
||||
|
@ -466,6 +475,20 @@ class SubiquityServer(Application):
|
|||
await controller.apply_autoinstall_config()
|
||||
await controller.configured()
|
||||
|
||||
def validate_autoinstall(self):
|
||||
with self.context.child("core_validation", level="INFO"):
|
||||
try:
|
||||
jsonschema.validate(self.autoinstall_config, self.base_schema)
|
||||
except ValidationError as original_exception:
|
||||
# SubiquityServer currently only checks for these sections
|
||||
# of autoinstall. Hardcode until we have better validation.
|
||||
section = "version or interative-sessions"
|
||||
new_exception: AutoinstallValidationError = AutoinstallValidationError(
|
||||
section,
|
||||
)
|
||||
|
||||
raise new_exception from original_exception
|
||||
|
||||
def load_autoinstall_config(self, *, only_early):
|
||||
log.debug(
|
||||
"load_autoinstall_config only_early %s file %s",
|
||||
|
@ -480,8 +503,7 @@ class SubiquityServer(Application):
|
|||
self.controllers.Reporting.setup_autoinstall()
|
||||
self.controllers.Reporting.start()
|
||||
self.controllers.Error.setup_autoinstall()
|
||||
with self.context.child("core_validation", level="INFO"):
|
||||
jsonschema.validate(self.autoinstall_config, self.base_schema)
|
||||
self.validate_autoinstall()
|
||||
self.controllers.Early.setup_autoinstall()
|
||||
else:
|
||||
for controller in self.controllers.instances:
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
import contextlib
|
||||
from unittest.mock import patch
|
||||
|
||||
from subiquity.server.autoinstall import AutoinstallValidationError
|
||||
from subiquity.server.controller import SubiquityController
|
||||
from subiquitycore.tests import SubiTestCase
|
||||
from subiquitycore.tests.mocks import make_app
|
||||
|
@ -41,7 +42,6 @@ class TestController(SubiTestCase):
|
|||
}
|
||||
self.controller.autoinstall_key = "sample"
|
||||
self.controller.autoinstall_key_alias = "sample-alias"
|
||||
self.controller.autoinstall_default = "default-data"
|
||||
self.controller.setup_autoinstall()
|
||||
mock_load.assert_called_once_with("some-sample-data")
|
||||
|
||||
|
@ -56,5 +56,36 @@ class TestController(SubiTestCase):
|
|||
mock_load.reset_mock()
|
||||
self.controller.autoinstall_key = "inexistent"
|
||||
self.controller.autoinstall_key_alias = "inexistent"
|
||||
self.controller.autoinstall_default = "default-data"
|
||||
self.controller.setup_autoinstall()
|
||||
mock_load.assert_called_once_with("default-data")
|
||||
|
||||
def test_autoinstall_validation(self):
|
||||
"""Test validation error type and no apport reporting"""
|
||||
|
||||
self.controller.autoinstall_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"some-key": {
|
||||
"type": "boolean",
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
self.bad_ai_data = {"some-key": "not a bool"}
|
||||
|
||||
self.controller.autoinstall_key = "some-key"
|
||||
|
||||
# Assert error type is correct
|
||||
with self.assertRaises(AutoinstallValidationError) as ctx:
|
||||
self.controller.validate_autoinstall(self.bad_ai_data)
|
||||
|
||||
exception = ctx.exception
|
||||
|
||||
# Assert error section is based on autoinstall_key
|
||||
self.assertEquals(exception.owner, "some-key")
|
||||
|
||||
# Assert apport report is not created
|
||||
# This only checks that controllers do not manually create an apport
|
||||
# report on validation. Should also be tested in Server
|
||||
self.controller.app.make_apport_report.assert_not_called()
|
||||
|
|
|
@ -17,7 +17,11 @@ import os
|
|||
import shlex
|
||||
from unittest.mock import Mock, patch
|
||||
|
||||
import jsonschema
|
||||
from jsonschema.validators import validator_for
|
||||
|
||||
from subiquity.common.types import PasswordKind
|
||||
from subiquity.server.autoinstall import AutoinstallValidationError
|
||||
from subiquity.server.server import (
|
||||
MetaController,
|
||||
SubiquityServer,
|
||||
|
@ -141,6 +145,56 @@ early-commands: ["{cmd}"]
|
|||
self.assertEqual(after_early, self.server.autoinstall_config)
|
||||
|
||||
|
||||
class TestAutoinstallValidation(SubiTestCase):
|
||||
async def asyncSetUp(self):
|
||||
opts = Mock()
|
||||
opts.dry_run = True
|
||||
opts.output_base = self.tmp_dir()
|
||||
opts.machine_config = "examples/machines/simple.json"
|
||||
self.server = SubiquityServer(opts, None)
|
||||
self.server.base_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"some-key": {
|
||||
"type": "boolean",
|
||||
},
|
||||
},
|
||||
}
|
||||
self.server.make_apport_report = Mock()
|
||||
|
||||
def test_valid_schema(self):
|
||||
"""Test that the expected autoinstall JSON schema is valid"""
|
||||
|
||||
JsonValidator: jsonschema.protocols.Validator = validator_for(
|
||||
SubiquityServer.base_schema
|
||||
)
|
||||
|
||||
JsonValidator.check_schema(SubiquityServer.base_schema)
|
||||
|
||||
def test_autoinstall_validation__error_type(self):
|
||||
"""Test that bad autoinstall data throws AutoinstallValidationError"""
|
||||
|
||||
bad_ai_data = {"some-key": "not a bool"}
|
||||
self.server.autoinstall_config = bad_ai_data
|
||||
|
||||
with self.assertRaises(AutoinstallValidationError):
|
||||
self.server.validate_autoinstall()
|
||||
|
||||
async def test_autoinstall_validation__no_error_report(self):
|
||||
"""Test no apport reporting"""
|
||||
|
||||
exception = AutoinstallValidationError("Mock")
|
||||
|
||||
loop = Mock()
|
||||
context = {"exception": exception}
|
||||
|
||||
with patch("subiquity.server.server.log"):
|
||||
with patch.object(self.server, "_run_error_cmds"):
|
||||
self.server._exception_handler(loop, context)
|
||||
|
||||
self.server.make_apport_report.assert_not_called()
|
||||
|
||||
|
||||
class TestMetaController(SubiTestCase):
|
||||
async def test_interactive_sections_not_present(self):
|
||||
mc = MetaController(make_app())
|
||||
|
|
|
@ -50,5 +50,6 @@ def make_app(model=None):
|
|||
app.log_syslog_id = None
|
||||
app.report_start_event = mock.Mock()
|
||||
app.report_finish_event = mock.Mock()
|
||||
app.make_apport_report = mock.Mock()
|
||||
|
||||
return app
|
||||
|
|
Loading…
Reference in New Issue