Add STAGE_DESC, STAGE_INFO, and STAGE_OPTS to stages
This commit adds semi-structured documentation to all osbuild stages and
assemblers. The variables added work like this:
* STAGE_DESC: Short description of the stage.
* STAGE_INFO: Longer documentation of the stage, including expected
behavior, required binaries, etc.
* STAGE_OPTS: A JSON Schema describing the stage's expected/allowed
options. (see https://json-schema.org/ for details)
It also has a little unittest to check stageinfo - specifically:
1. All (executable) stages in stages/* and assemblers/ must define strings named
STAGE_DESC, STAGE_INFO, and STAGE_OPTS
2. The contents of STAGE_OPTS must be valid JSON (if you put '{' '}'
around it)
3. STAGE_OPTS, if non-empty, should have a "properties" object
4. if STAGE_OPTS lists "required" properties, those need to be present
in the "properties" object.
The test is *not* included in .travis.yml because I'm not sure we want
to fail the build for this, but it's still helpful as a lint-style
check.
This commit is contained in:
parent
9d4b526a25
commit
6164b38fb9
25 changed files with 893 additions and 0 deletions
|
|
@ -3,6 +3,12 @@
|
|||
import json
|
||||
import sys
|
||||
|
||||
STAGE_DESC = "No-op assembler"
|
||||
STAGE_INFO = """
|
||||
No-op assembler. Produces no output, just prints a JSON dump of its options
|
||||
and then exits.
|
||||
"""
|
||||
STAGE_OPTS = ""
|
||||
def main(_tree, _output_dir, options):
|
||||
print("Not doing anything with these options:", json.dumps(options))
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,48 @@ import sys
|
|||
import tempfile
|
||||
import osbuild.remoteloop as remoteloop
|
||||
|
||||
STAGE_DESC = "Assemble a bootable partitioned disk image with qemu-img"
|
||||
STAGE_INFO = """
|
||||
Assemble a bootable partitioned disk image using `qemu-img`.
|
||||
|
||||
Creates a sparse MBR-partitioned disk image of the given `size`, with a single
|
||||
bootable partition containing an ext4 root filesystem.
|
||||
|
||||
Installs GRUB2 (using the buildhost's `/usr/lib/grub/i386-pc/boot.img` etc.) as
|
||||
the bootloader.
|
||||
|
||||
Copies the tree contents into the root filesystem and then converts the raw
|
||||
sparse image into the format requested with the `fmt` option.
|
||||
|
||||
Buildhost commands used: `truncate`, `mount`, `umount`, `sfdisk`,
|
||||
`grub2-mkimage`, `mkfs.ext4`, `qemu-img`.
|
||||
"""
|
||||
STAGE_OPTS = """
|
||||
"required": ["format", "filename", "ptuuid", "root_fs_uuid", "size"],
|
||||
"properties": {
|
||||
"format": {
|
||||
"description": "Image file format to use",
|
||||
"type": "string",
|
||||
"enum": ["raw", "qcow2", "vdi", "vmdk"]
|
||||
},
|
||||
"filename": {
|
||||
"description": "Image filename",
|
||||
"type": "string"
|
||||
},
|
||||
"ptuuid": {
|
||||
"description": "UUID for the disk image's partition table",
|
||||
"type": "string"
|
||||
},
|
||||
"root_fs_uuid": {
|
||||
"description": "UUID for the root filesystem",
|
||||
"type": "string"
|
||||
},
|
||||
"size": {
|
||||
"description": "Virtual disk size",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@contextlib.contextmanager
|
||||
def mount(source):
|
||||
|
|
|
|||
|
|
@ -8,6 +8,44 @@ import subprocess
|
|||
import sys
|
||||
import osbuild.remoteloop as remoteloop
|
||||
|
||||
STAGE_DESC = "Assemble tree into a raw ext4 filesystem image"
|
||||
STAGE_INFO = """
|
||||
Assemble the tree into a raw ext4 filesystem image named `filename`, with the
|
||||
UUID `root_fs_uuid`.
|
||||
|
||||
The image is a sparse file of the given `size`, which is created using the
|
||||
`truncate(1)` command. The `size` is an integer with an optional suffix:
|
||||
K,M,G,T,... (for powers of 1024) or KB,MB,GB,TB,... (powers of 1000).
|
||||
|
||||
NOTE: If the tree contents are larger than `size`, this assembler will fail.
|
||||
On the other hand, since the image is a sparse file, the unused parts of the
|
||||
image take up almost no disk space - so a 1GB tree in a 20GB image should not
|
||||
use much more than 1GB disk space.
|
||||
|
||||
The filesystem UUID should be a standard (RFC4122) UUID, which you can
|
||||
generate with uuid.uuid4() in Python, `uuidgen(1)` in a shell script, or
|
||||
read from `/proc/sys/kernel/random/uuid` if your kernel provides it.
|
||||
"""
|
||||
STAGE_OPTS = """
|
||||
"required": ["filename", "root_fs_uuid", "size"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Raw ext4 filesystem image filename",
|
||||
"type": "string"
|
||||
},
|
||||
"root_fs_uuid": {
|
||||
"description": "UUID for the filesystem",
|
||||
"type": "string",
|
||||
"pattern": "^[0-9A-Za-z]{8}(-[0-9A-Za-z]{4}){3}-[0-9A-Za-z]{12}$",
|
||||
"examples": ["9c6ae55b-cf88-45b8-84e8-64990759f39d"]
|
||||
},
|
||||
"size": {
|
||||
"description": "Maximum size of the filesystem",
|
||||
"type": "string",
|
||||
"examples": ["500M", "20GB"]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
@contextlib.contextmanager
|
||||
def mount(source, dest, *options):
|
||||
|
|
|
|||
|
|
@ -4,6 +4,37 @@ import json
|
|||
import subprocess
|
||||
import sys
|
||||
|
||||
STAGE_DESC = "Assemble a tar archive"
|
||||
STAGE_INFO = """
|
||||
Assembles the tree into a tar archive named `filename`.
|
||||
|
||||
Uses the buildhost's `tar` command, like: `tar -cf $FILENAME -C $TREE`
|
||||
|
||||
If the `compression` option is given, the archive will be compressed by passing
|
||||
the `--{compression}` option to `tar`. (This option is non-standard and might
|
||||
not work for anything other than GNU tar.)
|
||||
|
||||
Known options for `compression`: "bzip2", "xz", "lzip", "lzma", "lzop", "gzip".
|
||||
|
||||
Note that using `compression` does not add an extension to `filename`, so the
|
||||
caller is responsible for making sure that `compression` and `filename` match.
|
||||
|
||||
Buildhost commands used: `tar` and any named `compression` program.
|
||||
"""
|
||||
STAGE_OPTS = """
|
||||
"required": ["filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename for tar archive",
|
||||
"type": "string"
|
||||
},
|
||||
"compression": {
|
||||
"description": "Name of compression program",
|
||||
"type": "string",
|
||||
"enum": ["bzip2", "xz", "lzip", "lzma", "lzop", "gzip"]
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
def main(tree, output_dir, options):
|
||||
filename = options["filename"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue