Skip to content

Commit

Permalink
cloud: rename validate_cloud_init_schema
Browse files Browse the repository at this point in the history
Rename validate_cloud_init_schema to validate_cloud_init_top_level_keys
and rename get_schema_failure_keys to get_unknown_keys.

validate_cloud_init_schema wasn't really validating the whole
cloud-init schema, it's really just parsing the output for any
top-level keys that failed to validate. Let's rename it to what
it actually is doing: checking for bad top level keys.

Also renames the original CloudInitSchemaValidationError to
CloudInitSchemaTopLevelKeyError to reflect this change.
  • Loading branch information
Chris-Peterson444 committed Sep 17, 2024
1 parent 52bb9c3 commit efd289d
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 32 deletions.
28 changes: 16 additions & 12 deletions subiquity/cloudinit.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,11 @@


class CloudInitSchemaValidationError(NonReportableException):
"""Exception for cloud config schema validation failure.
"""Exception for cloud config schema validation failure."""


class CloudInitSchemaTopLevelKeyError(CloudInitSchemaValidationError):
"""Exception for when cloud-config top level keys fail to validate.
Attributes:
keys -- List of keys which are the cause of the failure
Expand All @@ -38,7 +42,7 @@ class CloudInitSchemaValidationError(NonReportableException):
def __init__(
self,
keys: list[str],
message: str = "Cloud config schema failed to validate.",
message: str = "Cloud config schema failed to validate top-level keys.",
) -> None:
super().__init__(message)
self.keys = keys
Expand Down Expand Up @@ -100,8 +104,8 @@ def read_legacy_status(stream):
return None


async def get_schema_failure_keys() -> list[str]:
"""Retrieve the keys causing schema failure."""
async def get_unknown_keys() -> list[str]:
"""Retrieve top-level keys causing schema failures, if any."""

cmd: list[str] = ["cloud-init", "schema", "--system"]
status_coro: Awaitable = arun_command(cmd, clean_locale=True)
Expand Down Expand Up @@ -149,22 +153,22 @@ async def cloud_init_status_wait() -> (bool, Optional[str]):
return (True, status)


async def validate_cloud_init_schema() -> None:
"""Check for cloud-init schema errors.
async def validate_cloud_init_top_level_keys() -> None:
"""Check for cloud-init schema errors in top-level keys.
Returns (None) if the cloud-config schema validated OK according to
cloud-init. Otherwise, a CloudInitSchemaValidationError is thrown
which contains a list of the keys which failed to validate.
cloud-init. Otherwise, a CloudInitSchemaTopLevelKeyError is thrown
which contains a list of the top-level keys which failed to validate.
Requires cloud-init supporting recoverable errors and extended status.
:return: None if cloud-init schema validated successfully.
:rtype: None
:raises CloudInitSchemaValidationError: If cloud-init schema did not validate
successfully.
:raises CloudInitSchemaTopLevelKeyError: If cloud-init schema did not
validate successfully.
"""
causes: list[str] = await get_schema_failure_keys()
causes: list[str] = await get_unknown_keys()

if causes:
raise CloudInitSchemaValidationError(keys=causes)
raise CloudInitSchemaTopLevelKeyError(keys=causes)

return None

Expand Down
8 changes: 4 additions & 4 deletions subiquity/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,12 +28,12 @@
from systemd import journal

from subiquity.cloudinit import (
CloudInitSchemaValidationError,
CloudInitSchemaTopLevelKeyError,
cloud_init_status_wait,
get_host_combined_cloud_config,
legacy_cloud_init_extract,
rand_user_password,
validate_cloud_init_schema,
validate_cloud_init_top_level_keys,
)
from subiquity.common.api.server import bind, controller_for_request
from subiquity.common.apidef import API
Expand Down Expand Up @@ -790,8 +790,8 @@ async def _extract_autoinstall_from_cloud_config(
context.enter() # publish start event

try:
await validate_cloud_init_schema()
except CloudInitSchemaValidationError as exc:
await validate_cloud_init_top_level_keys()
except CloudInitSchemaTopLevelKeyError as exc:
bad_keys: list[str] = exc.keys
raw_keys: list[str] = [f"{key!r}" for key in bad_keys]
context.warning(
Expand Down
14 changes: 9 additions & 5 deletions subiquity/server/tests/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import yaml
from jsonschema.validators import validator_for

from subiquity.cloudinit import CloudInitSchemaValidationError
from subiquity.cloudinit import CloudInitSchemaTopLevelKeyError
from subiquity.common.types import NonReportableError, PasswordKind
from subiquity.server.autoinstall import AutoinstallError, AutoinstallValidationError
from subiquity.server.nonreportable import NonReportableException
Expand Down Expand Up @@ -442,11 +442,13 @@ async def test_autoinstall_from_cloud_config(self, cloud_cfg, expected, throws):
cloud_data.pop("valid-cloud", None)
cloud_data.pop("autoinstall", None)

with patch("subiquity.server.server.validate_cloud_init_schema") as val_mock:
with patch(
"subiquity.server.server.validate_cloud_init_top_level_keys"
) as val_mock:
if len(cloud_data) == 0:
val_mock.return_value = True
else:
val_mock.side_effect = CloudInitSchemaValidationError(
val_mock.side_effect = CloudInitSchemaTopLevelKeyError(
keys=list(cloud_data.keys())
)

Expand All @@ -468,8 +470,10 @@ async def test_cloud_config_extract_KeyError(self):
self.server.base_schema = SubiquityServer.base_schema
self.pseudo_load_controllers()

with patch("subiquity.server.server.validate_cloud_init_schema") as val_mock:
val_mock.side_effect = CloudInitSchemaValidationError(
with patch(
"subiquity.server.server.validate_cloud_init_top_level_keys"
) as val_mock:
val_mock.side_effect = CloudInitSchemaTopLevelKeyError(
keys=["broadcast", "foobar"],
)

Expand Down
22 changes: 11 additions & 11 deletions subiquity/tests/test_cloudinit.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@

from subiquity.cloudinit import (
CLOUD_INIT_PW_SET,
CloudInitSchemaValidationError,
CloudInitSchemaTopLevelKeyError,
cloud_init_status_wait,
cloud_init_version,
get_schema_failure_keys,
get_unknown_keys,
legacy_cloud_init_extract,
rand_password,
rand_user_password,
read_json_extended_status,
read_legacy_status,
supports_format_json,
supports_recoverable_errors,
validate_cloud_init_schema,
validate_cloud_init_top_level_keys,
)
from subiquitycore.tests import SubiTestCase
from subiquitycore.tests.parameterized import parameterized
Expand Down Expand Up @@ -144,7 +144,7 @@ async def test_cloud_init_status_wait_legacy(self, m_wait_for):
self.assertEqual((True, "done"), await cloud_init_status_wait())


class TestCloudInitSchemaValidation(SubiTestCase):
class TestCloudInitTopLevelKeyValidation(SubiTestCase):
@parameterized.expand(
(
(
Expand Down Expand Up @@ -178,7 +178,7 @@ async def test_get_schema_failure_keys(self, msg, expected):
args=[], returncode=1, stderr=msg
)

bad_keys = await get_schema_failure_keys()
bad_keys = await get_unknown_keys()

self.assertEqual(bad_keys, expected)

Expand All @@ -193,7 +193,7 @@ async def test_get_schema_failure_malformed(self, wait_for_mock):
args=[], returncode=1, stderr=error_msg
)

bad_keys = await get_schema_failure_keys()
bad_keys = await get_unknown_keys()

self.assertEqual(bad_keys, [])

Expand All @@ -202,15 +202,15 @@ async def test_get_schema_failure_malformed(self, wait_for_mock):
async def test_no_schema_errors(self, wait_for_mock):
wait_for_mock.return_value = CompletedProcess(args=[], returncode=0, stderr="")

self.assertEqual(None, await validate_cloud_init_schema())
self.assertEqual(None, await validate_cloud_init_top_level_keys())

@patch("subiquity.cloudinit.get_schema_failure_keys")
@patch("subiquity.cloudinit.get_unknown_keys")
async def test_validate_cloud_init_schema(self, sources_mock):
mock_keys = ["key1", "key2"]
sources_mock.return_value = mock_keys

with self.assertRaises(CloudInitSchemaValidationError) as ctx:
await validate_cloud_init_schema()
with self.assertRaises(CloudInitSchemaTopLevelKeyError) as ctx:
await validate_cloud_init_top_level_keys()

self.assertEqual(mock_keys, ctx.exception.keys)

Expand All @@ -219,7 +219,7 @@ async def test_validate_cloud_init_schema(self, sources_mock):
@patch("subiquity.cloudinit.log")
async def test_get_schema_warn_on_timeout(self, log_mock, wait_for_mock):
wait_for_mock.side_effect = asyncio.TimeoutError()
sources = await get_schema_failure_keys()
sources = await get_unknown_keys()
log_mock.warning.assert_called()
self.assertEqual([], sources)

Expand Down

0 comments on commit efd289d

Please sign in to comment.