stages(kickstart): support autopart

This commit implements the `autopart` kickstart option and adds
matching tests.
This commit is contained in:
Michael Vogt 2023-11-07 20:21:09 +01:00 committed by Simon de Vlieger
parent f3d740aaf8
commit 5407f1cef1
2 changed files with 136 additions and 2 deletions

View file

@ -202,6 +202,66 @@ SCHEMA = r"""
"display_mode": {
"description": "Perform the Kickstart installation in the given display mode",
"enum": ["text", "graphical", "cmdline"]
},
"autopart": {
"description": "Automatically creates partitions",
"type": "object",
"not": {"required": ["pbkdf-iterations", "pbkdf-time"]},
"properties": {
"type": {
"description": "Selects one of the predefined automatic partitioning schemes you want to use",
"type": "string",
"enum": ["lvm", "btrfs", "plain", "thinp"]
},
"fstype": {
"description": "Specify a supported file system (such as ext4 or xfs) to replace the default when doing automatic partitioning",
"type": "string"
},
"nolvm": {
"description": "Do not use LVM or Btrfs for automatic partitioning. This option is equal to --type=plain",
"type": "boolean"
},
"encrypted": {
"description": "Encrypts all partitions",
"type": "boolean"
},
"passphrase": {
"description": "Provides a default system-wide passphrase for all encrypted devices",
"type": "string"
},
"escrowcert": {
"description": "Stores data encryption keys of all encrypted volumes as files in /root, encrypted using the X.509 certificate from the URL specified",
"type": "string"
},
"backuppassphrase": {
"description": "Adds a randomly-generated passphrase to each encrypted volume",
"type": "boolean"
},
"cipher": {
"description": "Specifies which type of encryption will be used if the Anaconda default aes-xts-plain64 is not satisfactory",
"type": "string"
},
"luks-version": {
"description": "Specifies which version of LUKS should be used to encrypt the system",
"type": "string"
},
"pbkdf": {
"description": "Sets Password-Based Key Derivation Function (PBKDF) algorithm for the LUKS keyslot",
"type": "string"
},
"pbkdf-memory": {
"description": "Sets the memory cost for PBKDF",
"type": "integer"
},
"pbkdf-time": {
"description": "Sets the number of milliseconds to spend with PBKDF passphrase processing",
"type": "integer"
},
"pbkdf-iterations": {
"description": "Sets the number of iterations for passphrase processing directly",
"type": "integer"
}
}
}
}
"""
@ -304,7 +364,25 @@ def make_reboot(options):
return cmd
def main(tree, options):
def make_autopart(options: Dict) -> str:
autopart = options.get("autopart")
if autopart is None:
return ""
cmd = "autopart"
for key in ["type", "fstype", "nolvm", "encrypted", "passphrase",
"escrowcert", "backuppassphrase", "cipher", "luks-version",
"pbkdf", "pbkdf-memory", "pbkdf-time", "pbkdf-iterations"]:
if key not in autopart:
continue
val = autopart[key]
if isinstance(val, bool):
cmd += f" --{key}"
else:
cmd += f" --{key}={val}"
return cmd
def main(tree, options): # pylint: disable=too-many-branches
path = options["path"].lstrip("/")
ostree = options.get("ostree")
@ -349,7 +427,9 @@ def main(tree, options):
display_mode = options.get("display_mode")
if display_mode:
config += [display_mode]
autopart = make_autopart(options)
if autopart:
config += [autopart]
reboot = make_reboot(options)
if reboot:
config += [reboot]

View file

@ -107,6 +107,56 @@ TEST_INPUT = [
({"display_mode": "text"}, "text"),
({"display_mode": "graphical"}, "graphical"),
({"display_mode": "cmdline"}, "cmdline"),
# autopart
({"autopart": {}}, "autopart"),
({"autopart": {"type": "plain"}}, "autopart --type=plain"),
({"autopart": {"fstype": "ext4"}}, "autopart --fstype=ext4"),
({"autopart": {"nolvm": True}}, "autopart --nolvm"),
({"autopart": {"encrypted": True}}, "autopart --encrypted"),
({"autopart": {"passphrase": "secret"}}, "autopart --passphrase=secret"),
({"autopart": {"escrowcert": "http://escrow"}}, "autopart --escrowcert=http://escrow"),
({"autopart": {"backuppassphrase": True}}, "autopart --backuppassphrase"),
({"autopart": {"cipher": "aes-xts-plain2048"}}, "autopart --cipher=aes-xts-plain2048"),
({"autopart": {"luks-version": "42"}}, "autopart --luks-version=42"),
({"autopart": {"pbkdf": "scrypt"}}, "autopart --pbkdf=scrypt"),
({"autopart": {"pbkdf-memory": 64}}, "autopart --pbkdf-memory=64"),
({"autopart": {"pbkdf-time": 128}}, "autopart --pbkdf-time=128"),
({"autopart": {"pbkdf-iterations": 256}}, "autopart --pbkdf-iterations=256"),
({
"lang": "en_US.UTF-8",
"keyboard": "us",
"timezone": "UTC",
"zerombr": True,
"clearpart": {
"all": True,
"drives": [
"sd*|hd*|vda",
"/dev/vdc"
]
},
"autopart": {
"type": "lvm",
"fstype": "zfs",
"nolvm": True,
"encrypted": True,
"passphrase": "secret2",
"escrowcert": "http://some-url",
"backuppassphrase": True,
"cipher": "twofish-cbc",
"luks-version": "2",
"pbkdf": "scrypt",
"pbkdf-memory": 256,
"pbkdf-time": 512,
# pbkdf-iterations cannot be used together with time
},
},
"lang en_US.UTF-8\nkeyboard us\ntimezone UTC\nzerombr\n" +
"clearpart --all --drives=sd*|hd*|vda,/dev/vdc\n" +
"autopart --type=lvm --fstype=zfs --nolvm --encrypted" +
" --passphrase=secret2 --escrowcert=http://some-url" +
" --backuppassphrase --cipher=twofish-cbc --luks-version=2" +
" --pbkdf=scrypt --pbkdf-memory=256 --pbkdf-time=512"
),
]
@ -186,6 +236,10 @@ def test_kickstart_valid(tmp_path, test_input, expected): # pylint: disable=unu
({"reboot": "random-string"}, "'random-string' is not valid "),
({"reboot": {"random": "option"}}, "{'random': 'option'} is not valid "),
({"display_mode": "invalid-mode"}, "'invalid-mode' is not one of "),
# autopart
({"autopart": {"type": "not-valid"}}, "'not-valid' is not one of ["),
# Only one of --pbkdf-{time,iterations} can be specified at the same time
({"autopart": {"pbkdf-time": 1, "pbkdf-iterations": 2}}, " should not be valid under "),
],
)
def test_schema_validation_bad_apples(test_data, expected_err):