Skip to content

Commit

Permalink
Merge pull request #2074 from Chris-Peterson444/kernel-crash-dumps-in…
Browse files Browse the repository at this point in the history
…troduction

Kernel crash dumps autoinstall
  • Loading branch information
Chris-Peterson444 authored Sep 16, 2024
2 parents 207edf1 + d3429d7 commit be25d93
Show file tree
Hide file tree
Showing 14 changed files with 260 additions and 3 deletions.
15 changes: 15 additions & 0 deletions autoinstall-schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,21 @@
}
]
},
"kernel-crash-dumps": {
"type": "object",
"properties": {
"enabled": {
"type": [
"boolean",
"null"
]
}
},
"required": [
"enabled"
],
"additionalProperties": false
},
"keyboard": {
"type": "object",
"properties": {
Expand Down
1 change: 1 addition & 0 deletions doc/.custom_wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ debconf
debian
dir
el
enablement
flavor
geoip
geolocation
Expand Down
49 changes: 49 additions & 0 deletions doc/reference/autoinstall-reference.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1190,6 +1190,55 @@ Example:
kernel:
flavour: hwe
.. _ai-kernel-crash-dumps:

kernel-crash-dumps
~~~~~~~~~~~~~~~~~~

* **type:** mapping, see below
* **default:** see below
* **can be interactive:** no

Toggle kernel crash dumps enablement.

In 24.10 and later, the default configuration will result in dynamic enablement of kernel crash dumps on the installed system using the ``kdump-tools`` package. On amd64, arm64, and s390x systems, if the system is detected to meet the minimum requirements for kernel crash dumps then they will be enabled. Otherwise, they will be disabled. More details about the minimum system requirements can be found in the following document (doesn't exist yet).

In pre-24.10, the default configuration will result in kernel crash dumps being disabled.

Default configuration:

.. code-block:: yaml
autoinstall:
# In 24.10 and later, allow kernel crash dumps to be enabled dynamically.
# In pre-24.10, kernel crash dumps will be disabled.
kernel-crash-dumps:
enabled: null
enabled
^^^^^^^

* **type:** boolean or null
* **default:** ``null``

Specify a boolean value to enable or disable kernel crash dumps. Set to ``null`` (default) to allow dynamic enablement.

If kernel crash dumps are to be disabled, whether determined dynamically or manually requested, the ``kdump-tools`` package will not be uninstalled but will be configured to ensure it is inactive in the target system.

Examples:

.. code-block:: yaml
autoinstall:
# Enable kernel crash dumps.
kernel-crash-dumps:
enabled: true
autoinstall:
# Disable kernel crash dumps.
kernel-crash-dumps:
enabled: false
.. _ai-timezone:

timezone
Expand Down
2 changes: 2 additions & 0 deletions examples/autoinstall/most-options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,5 @@ storage:
- {type: format, fstype: ext4, volume: raid-system, preserve: false, id: format-system}
- {type: mount, device: format-system, path: /, id: mount-system}
- {type: mount, device: format-boot, path: /boot, id: mount-boot, options: 'errors=remount-ro'}
kernel-crash-dumps:
enabled: false
3 changes: 1 addition & 2 deletions scripts/check-yaml-fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,7 @@ def main():
v = v[index]
if expected is None:
print(v)
else:
assert v == expected, "{!r} != {!r}".format(v, expected)
assert v == expected, "{!r} != {!r}".format(v, expected)


main()
4 changes: 4 additions & 0 deletions scripts/runtests.sh
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ python3 scripts/check-yaml-fields.py <(python3 scripts/check-yaml-fields.py $tmp
timezone='"Pacific/Guam"' \
ubuntu_advantage.token='"C1NWcZTHLteJXGVMM6YhvHDpGrhyy7"' \
'snap.commands=[snap install --channel=3.2/stable etcd]'
python3 scripts/check-yaml-fields.py "$tmpdir"/var/log/installer/curtin-install/subiquity-curthooks.conf \
kernel-crash-dumps.enabled=false
grep -q 'finish: subiquity/Install/install/postinstall/install_package1: SUCCESS: installing package1' \
$tmpdir/subiquity-server-debug.log
grep -q 'finish: subiquity/Install/install/postinstall/install_package2: SUCCESS: installing package2' \
Expand All @@ -193,6 +195,8 @@ 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
python3 scripts/check-yaml-fields.py "$tmpdir"/var/log/installer/curtin-install/subiquity-curthooks.conf \
kernel-crash-dumps.enabled=null

clean
testname=autoinstall-hybrid
Expand Down
2 changes: 1 addition & 1 deletion snapcraft.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ parts:

source: https://git.launchpad.net/curtin
source-type: git
source-commit: 364b719e189708255ff63b95078bc4f6bcf70540
source-commit: 40cae5c60fa9f4c495c7f61cde28862175f93ce2

override-pull: |
craftctl default
Expand Down
31 changes: 31 additions & 0 deletions subiquity/models/kernel_crash_dumps.py
Original file line number Diff line number Diff line change
@@ -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 General Public License as published by
# the Free Software Foundation, version 3.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import logging
from typing import Any

log = logging.getLogger("subiquity.models.kernel_crash_dumps")


class KernelCrashDumpsModel:
# Set to True/False via autoinstall. Defaults to None to let curtin know
# to do dynamic enablement based on release, arch, etc.
enabled: bool | None = None

def render(self) -> dict[str, Any]:
return {
"kernel-crash-dumps": {
"enabled": self.enabled,
},
}
2 changes: 2 additions & 0 deletions subiquity/models/subiquity.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ def SchemaProblem(x, y):
from .identity import IdentityModel
from .integrity import IntegrityModel
from .kernel import KernelModel
from .kernel_crash_dumps import KernelCrashDumpsModel
from .keyboard import KeyboardModel
from .locale import LocaleModel
from .mirror import MirrorModel
Expand Down Expand Up @@ -198,6 +199,7 @@ def __init__(
self.identity = IdentityModel()
self.integrity = IntegrityModel()
self.kernel = KernelModel()
self.kernel_crash_dumps = KernelCrashDumpsModel()
self.keyboard = KeyboardModel(self.root)
self.locale = LocaleModel(self.chroot_prefix)
self.mirror = MirrorModel()
Expand Down
33 changes: 33 additions & 0 deletions subiquity/models/tests/test_kernel_crash_dumps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

from subiquity.models.kernel_crash_dumps import KernelCrashDumpsModel
from subiquitycore.tests import SubiTestCase


class TestKernelCrashDumpsModel(SubiTestCase):
def setUp(self):
self.model = KernelCrashDumpsModel()

def test_automatic_decision(self):
"""Test the curtin config for curtin automatic enablement."""
expected = {"kernel-crash-dumps": {"enabled": None}}
self.assertEqual(expected, self.model.render())

def test_render_formatting(self):
"""Test the curtin config populates with correct formatting."""
config = {}
self.model.enabled = config["enabled"] = True
expected = {"kernel-crash-dumps": config}
self.assertEqual(expected, self.model.render())
2 changes: 2 additions & 0 deletions subiquity/server/controllers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
from .install import InstallController
from .integrity import IntegrityController
from .kernel import KernelController
from .kernel_crash_dumps import KernelCrashDumpsController
from .keyboard import KeyboardController
from .locale import LocaleController
from .mirror import MirrorController
Expand Down Expand Up @@ -54,6 +55,7 @@
"IntegrityController",
"InstallController",
"KernelController",
"KernelCrashDumpsController",
"KeyboardController",
"LateController",
"LocaleController",
Expand Down
49 changes: 49 additions & 0 deletions subiquity/server/controllers/kernel_crash_dumps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import logging
from typing import TypedDict

from subiquity.server.controller import NonInteractiveController

log = logging.getLogger("subiquity.server.controllers.kernel_crash_dumps")


class KernelCrashDumpsConfig(TypedDict, total=True):
enabled: bool | None


class KernelCrashDumpsController(NonInteractiveController):
model_name = "kernel_crash_dumps"
autoinstall_key = "kernel-crash-dumps"
autoinstall_schema = {
"type": "object",
"properties": {
"enabled": {"type": ["boolean", "null"]},
},
"required": ["enabled"],
"additionalProperties": False,
}

def load_autoinstall_data(self, data: KernelCrashDumpsConfig | None) -> None:
if data is None:
return
self.model.enabled = data["enabled"]

def make_autoinstall(self) -> dict[str, KernelCrashDumpsConfig]:
# Automatic determination implies no autoinstall
if self.model.enabled is None:
return {}

return {"enabled": self.model.enabled}
68 changes: 68 additions & 0 deletions subiquity/server/controllers/tests/test_kernel_crash_dumps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# Copyright 2024 Canonical, Ltd.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, version 3.
#
# 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 General Public License for more details.
#
# You should have received a copy of the GNU 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.models.kernel_crash_dumps import KernelCrashDumpsModel
from subiquity.server.autoinstall import AutoinstallValidationError
from subiquity.server.controllers.kernel_crash_dumps import KernelCrashDumpsController
from subiquitycore.tests import SubiTestCase
from subiquitycore.tests.mocks import make_app
from subiquitycore.tests.parameterized import parameterized


class TestKernelCrashDumpsSchema(SubiTestCase):
def test_valid_schema(self):
"""Test that the expected autoinstall JSON schema is valid"""

JsonValidator: jsonschema.protocols.Validator = validator_for(
KernelCrashDumpsController.autoinstall_schema
)

JsonValidator.check_schema(KernelCrashDumpsController.autoinstall_schema)


class TestKernelCrashDumpsAutoinstall(SubiTestCase):
def setUp(self):
app = make_app()
self.controller = KernelCrashDumpsController(app)
self.controller.model = KernelCrashDumpsModel()

@parameterized.expand(
(
# (config, valid)
# Valid configs
({"enabled": True}, True),
({"enabled": False}, True),
({"enabled": None}, True),
# Invalid configs
({}, False),
)
)
def test_valid_configs(self, config, valid):
"""Test autoinstall config validation behavior."""
if valid:
self.controller.validate_autoinstall(config)
else:
with self.assertRaises(AutoinstallValidationError):
self.controller.validate_autoinstall(config)

def test_make_autoinstall__default_empty(self):
self.assertEqual(self.controller.make_autoinstall(), {})

def test_make_autoinstall__non_default_format(self):
self.controller.model.enabled = False
expected = {"enabled": False}
self.assertEqual(self.controller.make_autoinstall(), expected)
2 changes: 2 additions & 0 deletions subiquity/server/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,7 @@ def get_installer_password_from_cloudinit_log():
"debconf_selections",
"filesystem",
"kernel",
"kernel_crash_dumps",
"keyboard",
"source",
},
Expand Down Expand Up @@ -258,6 +259,7 @@ class SubiquityServer(Application):
"Locale",
"Refresh",
"Kernel",
"KernelCrashDumps",
"Integrity",
"Keyboard",
"Zdev",
Expand Down

0 comments on commit be25d93

Please sign in to comment.