stages: externalize schemas
Copy all schemas into the relevant `.meta.json` files instead of having them contained inside the stages.
This commit is contained in:
parent
02b6d696ef
commit
bb58892571
296 changed files with 10435 additions and 9394 deletions
|
|
@ -1,56 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure basic aspects of the anaconda installer
|
||||
|
||||
Create an anaconda configuration file `90-osbuild.conf` in
|
||||
the folder `/etc/anaconda/conf.d` to configure anaconda.
|
||||
|
||||
Currently only the list of enabled kickstart modules is
|
||||
configurable via the `kickstart-modules` option.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"kickstart-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to enable",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"activatable-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to activate",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"forbidden-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to forbid",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"optional-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to activate but are allowed to fail",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
CONFIG = """
|
||||
# osbuild customizations
|
||||
|
|
|
|||
46
stages/org.osbuild.anaconda.meta.json
Normal file
46
stages/org.osbuild.anaconda.meta.json
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
{
|
||||
"summary": "Configure basic aspects of the anaconda installer",
|
||||
"description": [
|
||||
"Create an anaconda configuration file `90-osbuild.conf` in",
|
||||
"the folder `/etc/anaconda/conf.d` to configure anaconda.",
|
||||
"Currently only the list of enabled kickstart modules is",
|
||||
"configurable via the `kickstart-modules` option."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"properties": {
|
||||
"kickstart-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to enable",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"activatable-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to activate",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"forbidden-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to forbid",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
},
|
||||
"optional-modules": {
|
||||
"type": "array",
|
||||
"description": "Kick start modules to activate but are allowed to fail",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"minItems": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,26 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure authentication sources using authconfig.
|
||||
|
||||
Applies the default settings. Backups are cleared.
|
||||
|
||||
Notes:
|
||||
- Requires 'chroot' in the buildroot.
|
||||
- Runs the 'authconfig' binary from the image in the chroot.
|
||||
"""
|
||||
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"description": "Configure authentication sources."
|
||||
"""
|
||||
|
||||
|
||||
def main(tree):
|
||||
cmd = [
|
||||
|
|
|
|||
13
stages/org.osbuild.authconfig.meta.json
Normal file
13
stages/org.osbuild.authconfig.meta.json
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"summary": "Configure authentication sources using authconfig.",
|
||||
"description": [
|
||||
"Applies the default settings. Backups are cleared.",
|
||||
"Notes:",
|
||||
" - Requires 'chroot' in the buildroot.",
|
||||
" - Runs the 'authconfig' binary from the image in the chroot."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"description": "Configure authentication sources."
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Select system identity and authentication sources with authselect.
|
||||
|
||||
Sets system identity and authentication sources.
|
||||
|
||||
The stage calls `authselect select` to set authselect profile to 'profile'.
|
||||
Optionally a list of profile features to enable may be provided using 'features'
|
||||
option. The list of available profile features can be obtained by running
|
||||
`authselect list-features <profile>`.
|
||||
|
||||
Notes:
|
||||
- Requires 'chroot' in the buildroot.
|
||||
- Runs the 'authselect' binary from the image in the chroot.
|
||||
"""
|
||||
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["profile"],
|
||||
"description": "Select system identity and authentication sources.",
|
||||
"properties": {
|
||||
"profile": {
|
||||
"type": "string",
|
||||
"description": "Desired authselect profile to activate."
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
"description": "Features of the selected profile to activate.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
profile = options["profile"]
|
||||
|
|
|
|||
34
stages/org.osbuild.authselect.meta.json
Normal file
34
stages/org.osbuild.authselect.meta.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"summary": "Select system identity and authentication sources with authselect.",
|
||||
"description": [
|
||||
"Sets system identity and authentication sources.",
|
||||
"The stage calls `authselect select` to set authselect profile to 'profile'.",
|
||||
"Optionally a list of profile features to enable may be provided using 'features'",
|
||||
"option. The list of available profile features can be obtained by running",
|
||||
"`authselect list-features <profile>`.",
|
||||
"Notes:",
|
||||
" - Requires 'chroot' in the buildroot.",
|
||||
" - Runs the 'authselect' binary from the image in the chroot."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"profile"
|
||||
],
|
||||
"description": "Select system identity and authentication sources.",
|
||||
"properties": {
|
||||
"profile": {
|
||||
"type": "string",
|
||||
"description": "Desired authselect profile to activate."
|
||||
},
|
||||
"features": {
|
||||
"type": "array",
|
||||
"description": "Features of the selected profile to activate.",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Run bootc install to-filesystem
|
||||
|
||||
Note that this needs the disk.img in the inputs as one continous
|
||||
devices so that bootupd can install grub to the mbr. It also needs
|
||||
all relevant mount points for booting (e.g. /boot, /boot/efi) in
|
||||
mounted in the "mounts" path.
|
||||
|
||||
Buildhost commands used: bootc
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
|
@ -17,48 +6,6 @@ import tempfile
|
|||
import osbuild.api
|
||||
from osbuild.util import containers
|
||||
|
||||
CAPABILITIES = ["CAP_MAC_ADMIN"]
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["images"],
|
||||
"properties": {
|
||||
"images": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"root-ssh-authorized-keys": {
|
||||
"description": "array of SSH Public Keys to add to roots authorized_keys",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"kernel-args": {
|
||||
"description": "array of additional kernel arguments",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(options, inputs, paths):
|
||||
images = containers.parse_containers_input(inputs)
|
||||
|
|
|
|||
54
stages/org.osbuild.bootc.install-to-filesystem.meta.json
Normal file
54
stages/org.osbuild.bootc.install-to-filesystem.meta.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"summary": "Run bootc install to-filesystem",
|
||||
"description": [
|
||||
"Note that this needs the disk.img in the inputs as one continous",
|
||||
"devices so that bootupd can install grub to the mbr. It also needs",
|
||||
"all relevant mount points for booting (e.g. /boot, /boot/efi) in",
|
||||
"mounted in the \"mounts\" path.",
|
||||
"Buildhost commands used: bootc"
|
||||
],
|
||||
"capabilities": [
|
||||
"CAP_MAC_ADMIN"
|
||||
],
|
||||
"schema_2": {
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"images"
|
||||
],
|
||||
"properties": {
|
||||
"images": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"root-ssh-authorized-keys": {
|
||||
"description": "array of SSH Public Keys to add to roots authorized_keys",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"kernel-args": {
|
||||
"description": "array of additional kernel arguments",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Assemble a file system tree for a bootable iso
|
||||
|
||||
This stage prepares a file system tree for a bootable ISO, like the
|
||||
Anaconda installer. It follows the convention used by Lorax to
|
||||
create the boot isos: It takes an input `rootfs`, which will serve
|
||||
as the root file system. This is copied into a file with a `ext4`
|
||||
file system which in turn will be made into a squashfs file system.
|
||||
Options for controlling the root file-system creation can be given
|
||||
via `rootfs`, like it size and the compression to be used.
|
||||
|
||||
The boot loader is configured via the `isolinux` and `efi` options.
|
||||
Which combination makes sense depends on the targeted platform and
|
||||
architecture.
|
||||
The kernel and initrd are taken from the tree given via the `kernel`
|
||||
input, or if that was not specified, from `rootfs`. In either case
|
||||
it will look for the specified kernel in the `/boot` directory.
|
||||
Additionally kernel command line flags can passed via `kernel_opts`.
|
||||
|
||||
This stage has the `.mono` suffix to indicate that is a monolithic
|
||||
stage that could, and in the future will be, broken up into smaller
|
||||
pieces.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import re
|
||||
|
|
@ -34,119 +10,6 @@ import tempfile
|
|||
import osbuild.api
|
||||
import osbuild.remoteloop as remoteloop
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["product", "kernel", "isolabel"],
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "version"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"version": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"type": "string"
|
||||
},
|
||||
"isolabel": {
|
||||
"type": "string"
|
||||
},
|
||||
"efi": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["architectures", "vendor"],
|
||||
"properties": {
|
||||
"architectures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vendor": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"isolinux": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["enabled"],
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"debug": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kernel_opts": {
|
||||
"description": "Additional kernel boot options",
|
||||
"type": "string"
|
||||
},
|
||||
"templates": {
|
||||
"type": "string",
|
||||
"default": "99-generic"
|
||||
},
|
||||
"rootfs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"compression": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["method"],
|
||||
"properties": {
|
||||
"method": {
|
||||
"enum": ["gzip", "xz", "lz4"]
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bcj": {
|
||||
"enum": [
|
||||
"x86",
|
||||
"arm",
|
||||
"armthumb",
|
||||
"powerpc",
|
||||
"sparc",
|
||||
"ia64"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"description": "size in MB",
|
||||
"default": 3072
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["rootfs"],
|
||||
"properties": {
|
||||
"rootfs": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"kernel": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
LORAX_TEMPLATES = "/usr/share/lorax/templates.d"
|
||||
|
||||
|
|
|
|||
158
stages/org.osbuild.bootiso.mono.meta.json
Normal file
158
stages/org.osbuild.bootiso.mono.meta.json
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
{
|
||||
"summary": "Assemble a file system tree for a bootable iso",
|
||||
"description": [
|
||||
"This stage prepares a file system tree for a bootable ISO, like the",
|
||||
"Anaconda installer. It follows the convention used by Lorax to",
|
||||
"create the boot isos: It takes an input `rootfs`, which will serve",
|
||||
"as the root file system. This is copied into a file with a `ext4`",
|
||||
"file system which in turn will be made into a squashfs file system.",
|
||||
"Options for controlling the root file-system creation can be given",
|
||||
"via `rootfs`, like it size and the compression to be used.",
|
||||
"The boot loader is configured via the `isolinux` and `efi` options.",
|
||||
"Which combination makes sense depends on the targeted platform and",
|
||||
"architecture.",
|
||||
"The kernel and initrd are taken from the tree given via the `kernel`",
|
||||
"input, or if that was not specified, from `rootfs`. In either case",
|
||||
"it will look for the specified kernel in the `/boot` directory.",
|
||||
"Additionally kernel command line flags can passed via `kernel_opts`.",
|
||||
"This stage has the `.mono` suffix to indicate that is a monolithic",
|
||||
"stage that could, and in the future will be, broken up into smaller",
|
||||
"pieces."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"product",
|
||||
"kernel",
|
||||
"isolabel"
|
||||
],
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"type": "string"
|
||||
},
|
||||
"isolabel": {
|
||||
"type": "string"
|
||||
},
|
||||
"efi": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"architectures",
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"architectures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vendor": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"isolinux": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"enabled"
|
||||
],
|
||||
"properties": {
|
||||
"enabled": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"debug": {
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kernel_opts": {
|
||||
"description": "Additional kernel boot options",
|
||||
"type": "string"
|
||||
},
|
||||
"templates": {
|
||||
"type": "string",
|
||||
"default": "99-generic"
|
||||
},
|
||||
"rootfs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"compression": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"method"
|
||||
],
|
||||
"properties": {
|
||||
"method": {
|
||||
"enum": [
|
||||
"gzip",
|
||||
"xz",
|
||||
"lz4"
|
||||
]
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"bcj": {
|
||||
"enum": [
|
||||
"x86",
|
||||
"arm",
|
||||
"armthumb",
|
||||
"powerpc",
|
||||
"sparc",
|
||||
"ia64"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"size": {
|
||||
"type": "integer",
|
||||
"description": "size in MB",
|
||||
"default": 3072
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"rootfs"
|
||||
],
|
||||
"properties": {
|
||||
"rootfs": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"kernel": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,14 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Install GRUB on both BIOS and UEFI systems,
|
||||
ensuring that your bootloader stays up-to-date.
|
||||
|
||||
Bootupd supports updating GRUB and shim for
|
||||
UEFI firmware on x86_64 and aarch64,
|
||||
and GRUB for BIOS firmware on x86_64.
|
||||
The project is deployed in Fedora CoreOS and derivatives
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import json
|
||||
import os
|
||||
|
|
@ -18,84 +8,6 @@ import sys
|
|||
import osbuild.api
|
||||
from osbuild.util import ostree
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"deployment": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"default": {"enum": [false]}
|
||||
},
|
||||
"required": ["osname", "ref"]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"default": {"enum": [true]}
|
||||
},
|
||||
"not": {
|
||||
"anyOf": [
|
||||
{"required": ["osname"]},
|
||||
{"required": ["ref"]},
|
||||
{"required": ["serial"]}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"osname": {
|
||||
"description": "Name of the stateroot to be used in the deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"description": "OStree ref to create and use for deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The deployment serial (usually '0')",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"default": {
|
||||
"description": "Find and use the default ostree deployment",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"static-configs": {
|
||||
"description": "Install the grub configs defined for Fedora CoreOS",
|
||||
"type": "boolean"
|
||||
},
|
||||
"bios": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"required": ["device"],
|
||||
"properties": {
|
||||
"device": {
|
||||
"description": "Name of stage device to install GRUB for BIOS-based systems.",
|
||||
"type": "string"
|
||||
},
|
||||
"partition": {
|
||||
"description": "The partition on the stage device to install to, if installing to a partition",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def bind_mounts(sources, dest_root):
|
||||
|
|
|
|||
|
|
@ -1,15 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Transforms /usr/lib/ostree-boot into a bootupd-compatible update payload.
|
||||
|
||||
Scrapes metadata (e.g. RPM versions) about shim/grub and puts them along with their component files in
|
||||
`/usr/lib/bootupd/updates/`.
|
||||
|
||||
Notes:
|
||||
- Requires 'chroot' in the buildroot.
|
||||
- Runs the 'bootupctl' binary from the image in the chroot.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -17,12 +6,6 @@ import sys
|
|||
import osbuild.api
|
||||
from osbuild.util.mnt import MountGuard, MountPermissions
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree):
|
||||
with MountGuard() as mounter:
|
||||
|
|
|
|||
15
stages/org.osbuild.bootupd.gen-metadata.meta.json
Normal file
15
stages/org.osbuild.bootupd.gen-metadata.meta.json
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
"summary": "Transforms /usr/lib/ostree-boot into a bootupd-compatible update payload.",
|
||||
"description": [
|
||||
"Scrapes metadata (e.g. RPM versions) about shim/grub and puts them along with their component files in",
|
||||
"`/usr/lib/bootupd/updates/`.",
|
||||
"Notes:",
|
||||
" - Requires 'chroot' in the buildroot.",
|
||||
" - Runs the 'bootupctl' binary from the image in the chroot."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
111
stages/org.osbuild.bootupd.meta.json
Normal file
111
stages/org.osbuild.bootupd.meta.json
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
{
|
||||
"summary": "Install GRUB on both BIOS and UEFI systems,\nensuring that your bootloader stays up-to-date.",
|
||||
"description": [
|
||||
"Bootupd supports updating GRUB and shim for",
|
||||
"UEFI firmware on x86_64 and aarch64,",
|
||||
"and GRUB for BIOS firmware on x86_64.",
|
||||
"The project is deployed in Fedora CoreOS and derivatives"
|
||||
],
|
||||
"schema_2": {
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"deployment": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"default": {
|
||||
"enum": [
|
||||
false
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"osname",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"default": {
|
||||
"enum": [
|
||||
true
|
||||
]
|
||||
}
|
||||
},
|
||||
"not": {
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"osname"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"serial"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"osname": {
|
||||
"description": "Name of the stateroot to be used in the deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"description": "OStree ref to create and use for deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The deployment serial (usually '0')",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"default": {
|
||||
"description": "Find and use the default ostree deployment",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"static-configs": {
|
||||
"description": "Install the grub configs defined for Fedora CoreOS",
|
||||
"type": "boolean"
|
||||
},
|
||||
"bios": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"required": [
|
||||
"device"
|
||||
],
|
||||
"properties": {
|
||||
"device": {
|
||||
"description": "Name of stage device to install GRUB for BIOS-based systems.",
|
||||
"type": "string"
|
||||
},
|
||||
"partition": {
|
||||
"description": "The partition on the stage device to install to, if installing to a partition",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create subvolumes on a mounted btrfs partition.
|
||||
|
||||
See `btrfs`(8).
|
||||
|
||||
Buildhost commands used: `btrfs`.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"subvolumes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(paths, options):
|
||||
volume = paths["mounts"]
|
||||
|
|
|
|||
36
stages/org.osbuild.btrfs.subvol.meta.json
Normal file
36
stages/org.osbuild.btrfs.subvol.meta.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"summary": "Create subvolumes on a mounted btrfs partition.",
|
||||
"description": [
|
||||
"See `btrfs`(8).",
|
||||
"Buildhost commands used: `btrfs`."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"subvolumes": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create a /.buildstamp file describing the system
|
||||
|
||||
This will create a './buildstamp' with the specified parameters.
|
||||
"""
|
||||
|
||||
import configparser
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": true,
|
||||
"required": ["arch", "product", "version", "final"],
|
||||
"properties": {
|
||||
"arch": {
|
||||
"description": "Build architecture.",
|
||||
"type": "string"
|
||||
},
|
||||
"product": {
|
||||
"description": "The product name.",
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"description": "The version .",
|
||||
"type": "string"
|
||||
},
|
||||
"final": {
|
||||
"description": "The product.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"variant": {
|
||||
"description": "The variant of the product.",
|
||||
"type": "string"
|
||||
},
|
||||
"bugurl": {
|
||||
"description": "The bugurl of the product.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
buildarch = options["arch"]
|
||||
|
|
|
|||
41
stages/org.osbuild.buildstamp.meta.json
Normal file
41
stages/org.osbuild.buildstamp.meta.json
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"summary": "Create a /.buildstamp file describing the system",
|
||||
"description": [
|
||||
"This will create a './buildstamp' with the specified parameters."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"required": [
|
||||
"arch",
|
||||
"product",
|
||||
"version",
|
||||
"final"
|
||||
],
|
||||
"properties": {
|
||||
"arch": {
|
||||
"description": "Build architecture.",
|
||||
"type": "string"
|
||||
},
|
||||
"product": {
|
||||
"description": "The product name.",
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"description": "The version .",
|
||||
"type": "string"
|
||||
},
|
||||
"final": {
|
||||
"description": "The product.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"variant": {
|
||||
"description": "The variant of the product.",
|
||||
"type": "string"
|
||||
},
|
||||
"bugurl": {
|
||||
"description": "The bugurl of the product.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Runs `chattr` to set file/directory attributes.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -11,38 +7,6 @@ from urllib.parse import ParseResult, urlparse
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^mount:\/\/[^\/]+\/|^tree:\/\/\/": {
|
||||
"type": "object",
|
||||
"required": ["immutable"],
|
||||
"properties": {
|
||||
"immutable": {
|
||||
"type": "boolean",
|
||||
"description": "Make the file/directory immutable",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def parse_mount(url: ParseResult, args: Dict):
|
||||
name = url.netloc
|
||||
|
|
|
|||
37
stages/org.osbuild.chattr.meta.json
Normal file
37
stages/org.osbuild.chattr.meta.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"summary": "Runs `chattr` to set file/directory attributes.",
|
||||
"description": [],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^mount://[^/]+/|^tree:///": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"immutable"
|
||||
],
|
||||
"properties": {
|
||||
"immutable": {
|
||||
"type": "boolean",
|
||||
"description": "Make the file/directory immutable",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Change file mode bits
|
||||
|
||||
Change the file mode bits of one or more files or directories inside the tree.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -12,35 +6,6 @@ import sys
|
|||
import osbuild.api
|
||||
from osbuild.util.path import in_tree
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^\\/(?!\\.\\.)((?!\\/\\.\\.\\/).)+$": {
|
||||
"type": "object",
|
||||
"required": ["mode"],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "Symbolic or numeric octal mode"
|
||||
},
|
||||
"recursive": {
|
||||
"type": "boolean",
|
||||
"description": "Change modes recursively",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def chmod(path: str, mode: str, recursive: bool):
|
||||
arguments = [mode]
|
||||
|
|
|
|||
36
stages/org.osbuild.chmod.meta.json
Normal file
36
stages/org.osbuild.chmod.meta.json
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
{
|
||||
"summary": "Change file mode bits",
|
||||
"description": [
|
||||
"Change the file mode bits of one or more files or directories inside the tree."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^\\/(?!\\.\\.)((?!\\/\\.\\.\\/).)+$": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"mode"
|
||||
],
|
||||
"properties": {
|
||||
"mode": {
|
||||
"type": "string",
|
||||
"description": "Symbolic or numeric octal mode"
|
||||
},
|
||||
"recursive": {
|
||||
"type": "boolean",
|
||||
"description": "Change modes recursively",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,73 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Change file owner and group
|
||||
|
||||
Change the file user and/or group ownership of one or more files or directories inside the tree.
|
||||
|
||||
Notes:
|
||||
- Requires 'chroot' in the buildroot.
|
||||
- Runs the 'chown' binary from the image in the chroot.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^\\/(?!\\.\\.)((?!\\/\\.\\.\\/).)+$": {
|
||||
"type": "object",
|
||||
"anyOf": [
|
||||
{"required" : ["user"]},
|
||||
{"required" : ["group"]}
|
||||
],
|
||||
"properties": {
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9_.][A-Za-z0-9_.-]{0,31}$"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
],
|
||||
"description": "User name or UID"
|
||||
},
|
||||
"group": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9_][A-Za-z0-9_-]{0,31}$"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
],
|
||||
"description": "Group name or GID"
|
||||
},
|
||||
"recursive": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Change ownership recursively"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
for path, cmdargs in options["items"].items():
|
||||
|
|
|
|||
70
stages/org.osbuild.chown.meta.json
Normal file
70
stages/org.osbuild.chown.meta.json
Normal file
|
|
@ -0,0 +1,70 @@
|
|||
{
|
||||
"summary": "Change file owner and group",
|
||||
"description": [
|
||||
"Change the file user and/or group ownership of one or more files or directories inside the tree.",
|
||||
"Notes:",
|
||||
" - Requires 'chroot' in the buildroot.",
|
||||
" - Runs the 'chown' binary from the image in the chroot."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"patternProperties": {
|
||||
"^\\/(?!\\.\\.)((?!\\/\\.\\.\\/).)+$": {
|
||||
"type": "object",
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"user"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"group"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"user": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9_.][A-Za-z0-9_.-]{0,31}$"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
],
|
||||
"description": "User name or UID"
|
||||
},
|
||||
"group": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"pattern": "^[A-Za-z0-9_][A-Za-z0-9_-]{0,31}$"
|
||||
},
|
||||
{
|
||||
"type": "number",
|
||||
"minimum": 0
|
||||
}
|
||||
],
|
||||
"description": "Group name or GID"
|
||||
},
|
||||
"recursive": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Change ownership recursively"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,100 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure chrony to set system time from the network.
|
||||
|
||||
Configures `chrony` by modifying `/etc/chrony.conf`.
|
||||
|
||||
Before new values are added to the chrony configuration, all lines starting with
|
||||
"server", "pool" or "peer" are removed.
|
||||
|
||||
The 'timeservers' option provides a very high-level way of configuring chronyd
|
||||
with specific timeservers. Its value is a list of strings representing the
|
||||
hostname or IP address of the timeserver. For each list item, the following
|
||||
line will be added to the configuration:
|
||||
`server <HOSTNAME/IP> iburst`
|
||||
|
||||
The 'servers' option provides a direct mapping to the `server` directive from
|
||||
chrony configuration. Its value is a list of dictionaries representing each
|
||||
timeserver which should be added to the configuration. For each list item,
|
||||
a `server` directive will be added the configuration. Currently supported
|
||||
subset of options which can be specified for each timeserver item:
|
||||
- 'hostname' (REQUIRED)
|
||||
- 'minpoll'
|
||||
- 'maxpoll'
|
||||
- 'iburst' (defaults to true)
|
||||
- 'prefer' (defaults to false)
|
||||
|
||||
The 'leapsectz' option configures chrony behavior related to automatic checking
|
||||
of the next occurrence of the leap second, using the provided timezone. Its
|
||||
value is a string representing a timezone from the system tz database (e.g.
|
||||
'right/UTC'). If an empty string is provided, then all occurrences of
|
||||
'leapsectz' directive are removed from the configuration.
|
||||
|
||||
Constraints:
|
||||
- Exactly one of 'timeservers' or 'servers' options must be provided.
|
||||
"""
|
||||
|
||||
|
||||
import re
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{"required": ["timeservers"]},
|
||||
{"required": ["servers"]}
|
||||
],
|
||||
"properties": {
|
||||
"timeservers": {
|
||||
"type": "array",
|
||||
"items": { "type": "string" },
|
||||
"description": "Array of NTP server addresses."
|
||||
},
|
||||
"servers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"required": ["hostname"],
|
||||
"properties": {
|
||||
"hostname": {
|
||||
"type": "string",
|
||||
"description": "Hostname or IP address of a NTP server."
|
||||
},
|
||||
"minpoll": {
|
||||
"type": "integer",
|
||||
"description": "Specifies the minimum interval between requests sent to the server as a power of 2 in seconds.",
|
||||
"minimum": -6,
|
||||
"maximum": 24
|
||||
},
|
||||
"maxpoll": {
|
||||
"type": "integer",
|
||||
"description": "Specifies the maximum interval between requests sent to the server as a power of 2 in seconds.",
|
||||
"minimum": -6,
|
||||
"maximum": 24
|
||||
},
|
||||
"iburst": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Configures chronyd behavior related to burst requests on startup."
|
||||
},
|
||||
"prefer": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Prefer this source over sources without the prefer option."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"leapsectz": {
|
||||
"type": "string",
|
||||
"description": "Timezone used by chronyd to determine when will the next leap second occur. Empty value will remove the option."
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
DELETE_TIME_SOURCE_LINE_REGEX = re.compile(r"(server|pool|peer) ")
|
||||
DELETE_LEAPSECTZ_LINE_REGEX = re.compile(r"leapsectz ")
|
||||
|
|
|
|||
96
stages/org.osbuild.chrony.meta.json
Normal file
96
stages/org.osbuild.chrony.meta.json
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"summary": "Configure chrony to set system time from the network.",
|
||||
"description": [
|
||||
"Configures `chrony` by modifying `/etc/chrony.conf`.",
|
||||
"Before new values are added to the chrony configuration, all lines starting with",
|
||||
"\"server\", \"pool\" or \"peer\" are removed.",
|
||||
"The 'timeservers' option provides a very high-level way of configuring chronyd",
|
||||
"with specific timeservers. Its value is a list of strings representing the",
|
||||
"hostname or IP address of the timeserver. For each list item, the following",
|
||||
"line will be added to the configuration:",
|
||||
"`server <HOSTNAME/IP> iburst`",
|
||||
"The 'servers' option provides a direct mapping to the `server` directive from",
|
||||
"chrony configuration. Its value is a list of dictionaries representing each",
|
||||
"timeserver which should be added to the configuration. For each list item,",
|
||||
"a `server` directive will be added the configuration. Currently supported",
|
||||
"subset of options which can be specified for each timeserver item:",
|
||||
" - 'hostname' (REQUIRED)",
|
||||
" - 'minpoll'",
|
||||
" - 'maxpoll'",
|
||||
" - 'iburst' (defaults to true)",
|
||||
" - 'prefer' (defaults to false)",
|
||||
"The 'leapsectz' option configures chrony behavior related to automatic checking",
|
||||
"of the next occurrence of the leap second, using the provided timezone. Its",
|
||||
"value is a string representing a timezone from the system tz database (e.g.",
|
||||
"'right/UTC'). If an empty string is provided, then all occurrences of",
|
||||
"'leapsectz' directive are removed from the configuration.",
|
||||
"Constraints:",
|
||||
" - Exactly one of 'timeservers' or 'servers' options must be provided."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"timeservers"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"servers"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"timeservers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
},
|
||||
"description": "Array of NTP server addresses."
|
||||
},
|
||||
"servers": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"required": [
|
||||
"hostname"
|
||||
],
|
||||
"properties": {
|
||||
"hostname": {
|
||||
"type": "string",
|
||||
"description": "Hostname or IP address of a NTP server."
|
||||
},
|
||||
"minpoll": {
|
||||
"type": "integer",
|
||||
"description": "Specifies the minimum interval between requests sent to the server as a power of 2 in seconds.",
|
||||
"minimum": -6,
|
||||
"maximum": 24
|
||||
},
|
||||
"maxpoll": {
|
||||
"type": "integer",
|
||||
"description": "Specifies the maximum interval between requests sent to the server as a power of 2 in seconds.",
|
||||
"minimum": -6,
|
||||
"maximum": 24
|
||||
},
|
||||
"iburst": {
|
||||
"type": "boolean",
|
||||
"default": true,
|
||||
"description": "Configures chronyd behavior related to burst requests on startup."
|
||||
},
|
||||
"prefer": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "Prefer this source over sources without the prefer option."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"leapsectz": {
|
||||
"type": "string",
|
||||
"description": "Timezone used by chronyd to determine when will the next leap second occur. Empty value will remove the option."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,49 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Bind a LUKS device using the specified policy.
|
||||
|
||||
Buildhost commands used: `clevis`, `clevis-luks`, `clevis-pin-*`.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": ["device"],
|
||||
"properties": {
|
||||
"device": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["passphrase", "pin", "policy"],
|
||||
"properties": {
|
||||
"passphrase": {
|
||||
"description": "Passphrase to unlock the container",
|
||||
"type": "string"
|
||||
},
|
||||
"pin": {
|
||||
"description": "The pin to use",
|
||||
"type": "string"
|
||||
},
|
||||
"policy": {
|
||||
"description": "Policy to use with the given pin",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(devices, options):
|
||||
device = devices["device"]
|
||||
|
|
|
|||
43
stages/org.osbuild.clevis.luks-bind.meta.json
Normal file
43
stages/org.osbuild.clevis.luks-bind.meta.json
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
{
|
||||
"summary": "Bind a LUKS device using the specified policy.",
|
||||
"description": [
|
||||
"Buildhost commands used: `clevis`, `clevis-luks`, `clevis-pin-*`."
|
||||
],
|
||||
"schema_2": {
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true,
|
||||
"required": [
|
||||
"device"
|
||||
],
|
||||
"properties": {
|
||||
"device": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"passphrase",
|
||||
"pin",
|
||||
"policy"
|
||||
],
|
||||
"properties": {
|
||||
"passphrase": {
|
||||
"description": "Passphrase to unlock the container",
|
||||
"type": "string"
|
||||
},
|
||||
"pin": {
|
||||
"description": "The pin to use",
|
||||
"type": "string"
|
||||
},
|
||||
"policy": {
|
||||
"description": "Policy to use with the given pin",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,146 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure cloud-init
|
||||
|
||||
The 'config' option allows to configure cloud-init by creating a
|
||||
configuration file under `/etc/cloud/cloud.cfg.d` with the name
|
||||
specified by `filename`.
|
||||
|
||||
Constrains:
|
||||
- Each configuration file definition must contain at least one configuration
|
||||
|
||||
Currently supported subset of cloud-init configuration:
|
||||
- 'system_info' section
|
||||
- 'default_user' section
|
||||
- 'name' option
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import yaml
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"definitions": {
|
||||
"reporting_handlers": {
|
||||
"type": "string",
|
||||
"enum": ["log", "print", "webhook", "hyperv"]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["config", "filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Name of the cloud-init configuration file.",
|
||||
"pattern": "^[\\w.-]{1,251}\\.cfg$"
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "cloud-init configuration",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"system_info": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "'system_info' configuration section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"default_user": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "Configuration of the 'default' user created by cloud-init.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "username of the 'default' user."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reporting": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Define reporting endpoints.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"logging": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/definitions/reporting_handlers"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/definitions/reporting_handlers"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"datasource_list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": ["Azure"]
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "object",
|
||||
"description": "Sources of configuration data for cloud-init.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"Azure": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"apply_network_config": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use network configuration described by Azure’s IMDS endpoint",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"init": {
|
||||
"description": "Redirect the output of the init stage",
|
||||
"type": "string"
|
||||
},
|
||||
"config": {
|
||||
"description": "Redirect the output of the config stage",
|
||||
"type": "string"
|
||||
},
|
||||
"final": {
|
||||
"description": "Redirect the output of the final stage",
|
||||
"type": "string"
|
||||
},
|
||||
"all": {
|
||||
"description": "Redirect the output of all stages",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# Class representing the 'datasource_list' configuration option,
|
||||
# allowing to define a custom YAML dumper for it.
|
||||
|
|
|
|||
142
stages/org.osbuild.cloud-init.meta.json
Normal file
142
stages/org.osbuild.cloud-init.meta.json
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
{
|
||||
"summary": "Configure cloud-init",
|
||||
"description": [
|
||||
"The 'config' option allows to configure cloud-init by creating a",
|
||||
"configuration file under `/etc/cloud/cloud.cfg.d` with the name",
|
||||
"specified by `filename`.",
|
||||
"Constrains:",
|
||||
" - Each configuration file definition must contain at least one configuration",
|
||||
"Currently supported subset of cloud-init configuration:",
|
||||
" - 'system_info' section",
|
||||
" - 'default_user' section",
|
||||
" - 'name' option"
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"reporting_handlers": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"log",
|
||||
"print",
|
||||
"webhook",
|
||||
"hyperv"
|
||||
]
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"config",
|
||||
"filename"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Name of the cloud-init configuration file.",
|
||||
"pattern": "^[\\w.-]{1,251}\\.cfg$"
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "cloud-init configuration",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"system_info": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "'system_info' configuration section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"default_user": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "Configuration of the 'default' user created by cloud-init.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "username of the 'default' user."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"reporting": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Define reporting endpoints.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"logging": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/definitions/reporting_handlers"
|
||||
}
|
||||
}
|
||||
},
|
||||
"telemetry": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"type": {
|
||||
"$ref": "#/definitions/reporting_handlers"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"datasource_list": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"Azure"
|
||||
]
|
||||
}
|
||||
},
|
||||
"datasource": {
|
||||
"type": "object",
|
||||
"description": "Sources of configuration data for cloud-init.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"Azure": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"apply_network_config": {
|
||||
"type": "boolean",
|
||||
"description": "Whether to use network configuration described by Azure\u2019s IMDS endpoint",
|
||||
"default": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"output": {
|
||||
"type": "object",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"init": {
|
||||
"description": "Redirect the output of the init stage",
|
||||
"type": "string"
|
||||
},
|
||||
"config": {
|
||||
"description": "Redirect the output of the config stage",
|
||||
"type": "string"
|
||||
},
|
||||
"final": {
|
||||
"description": "Redirect the output of the final stage",
|
||||
"type": "string"
|
||||
},
|
||||
"all": {
|
||||
"description": "Redirect the output of all stages",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Deploy a container.
|
||||
|
||||
Buildhost commands used: podman skopeo
|
||||
"""
|
||||
import contextlib
|
||||
import os
|
||||
import random
|
||||
|
|
@ -14,33 +9,6 @@ import sys
|
|||
import osbuild.api
|
||||
from osbuild.util import containers
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["images"],
|
||||
"properties": {
|
||||
"images": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"exclude": {
|
||||
"type": "array",
|
||||
"description": "Exclude paths from the deployment",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
@contextlib.contextmanager
|
||||
def mount_container(image_tag):
|
||||
|
|
|
|||
34
stages/org.osbuild.container-deploy.meta.json
Normal file
34
stages/org.osbuild.container-deploy.meta.json
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
{
|
||||
"summary": "Deploy a container.",
|
||||
"description": [
|
||||
"Buildhost commands used: podman skopeo"
|
||||
],
|
||||
"schema_2": {
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"images"
|
||||
],
|
||||
"properties": {
|
||||
"images": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"exclude": {
|
||||
"type": "array",
|
||||
"description": "Exclude paths from the deployment",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,12 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Edit containers-storage.conf(5) files.
|
||||
|
||||
This stage can be used to create or modify `containers-storage.conf`
|
||||
configuration files. The default strategy is to merge the specified
|
||||
options with the existing options.
|
||||
"""
|
||||
|
||||
import contextlib
|
||||
import os
|
||||
import sys
|
||||
|
|
@ -19,126 +11,6 @@ except ModuleNotFoundError:
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"definitions": {
|
||||
"storage": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"driver": {
|
||||
"description": "container storage driver.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"overlay",
|
||||
"vfs",
|
||||
"devmapper",
|
||||
"aufs",
|
||||
"btrfs",
|
||||
"zfs"
|
||||
]
|
||||
},
|
||||
"graphroot": {
|
||||
"description": "container storage graph directory.",
|
||||
"type": "string"
|
||||
},
|
||||
"runroot": {
|
||||
"description": "container storage run directory.",
|
||||
"type": "string"
|
||||
},
|
||||
"transient_store": {
|
||||
"description": "Make the container store not persist across reboot.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"options": {
|
||||
"$ref": "#/definitions/storage-options"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage-options": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"additionalimagestores": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"pull_options": {
|
||||
"$ref": "#/definitions/storage-options-pulloptions"
|
||||
},
|
||||
"overlay": {
|
||||
"$ref": "#/definitions/storage-options-overlay"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage-options-pulloptions": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"enable_partial_images": {
|
||||
"type": "string",
|
||||
"enum": ["true", "false"]
|
||||
},
|
||||
"use_hard_links": {
|
||||
"type": "string",
|
||||
"enum": ["true", "false"]
|
||||
},
|
||||
"convert_images": {
|
||||
"type": "string",
|
||||
"enum": ["true", "false"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage-options-overlay": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"mountopt": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["config"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "location of the configuration file.",
|
||||
"default": "/etc/containers/storage.conf",
|
||||
"enum": [
|
||||
"/etc/containers/storage.conf",
|
||||
"/usr/share/containers/storage.conf"
|
||||
]
|
||||
},
|
||||
"filebase": {
|
||||
"type": "string",
|
||||
"description": "Read the base configuration from this file."
|
||||
},
|
||||
"comment": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "storage configuration",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"storage": {
|
||||
"$ref": "#/definitions/storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
DEFAULT_LOCATION = "/etc/containers/storage.conf"
|
||||
|
||||
|
|
|
|||
139
stages/org.osbuild.containers.storage.conf.meta.json
Normal file
139
stages/org.osbuild.containers.storage.conf.meta.json
Normal file
|
|
@ -0,0 +1,139 @@
|
|||
{
|
||||
"summary": "Edit containers-storage.conf(5) files.",
|
||||
"description": [
|
||||
"This stage can be used to create or modify `containers-storage.conf`",
|
||||
"configuration files. The default strategy is to merge the specified",
|
||||
"options with the existing options."
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"storage": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"driver": {
|
||||
"description": "container storage driver.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"overlay",
|
||||
"vfs",
|
||||
"devmapper",
|
||||
"aufs",
|
||||
"btrfs",
|
||||
"zfs"
|
||||
]
|
||||
},
|
||||
"graphroot": {
|
||||
"description": "container storage graph directory.",
|
||||
"type": "string"
|
||||
},
|
||||
"runroot": {
|
||||
"description": "container storage run directory.",
|
||||
"type": "string"
|
||||
},
|
||||
"transient_store": {
|
||||
"description": "Make the container store not persist across reboot.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"options": {
|
||||
"$ref": "#/definitions/storage-options"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage-options": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"additionalimagestores": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"pull_options": {
|
||||
"$ref": "#/definitions/storage-options-pulloptions"
|
||||
},
|
||||
"overlay": {
|
||||
"$ref": "#/definitions/storage-options-overlay"
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage-options-pulloptions": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"enable_partial_images": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
},
|
||||
"use_hard_links": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
},
|
||||
"convert_images": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"true",
|
||||
"false"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"storage-options-overlay": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"mountopt": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"config"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "location of the configuration file.",
|
||||
"default": "/etc/containers/storage.conf",
|
||||
"enum": [
|
||||
"/etc/containers/storage.conf",
|
||||
"/usr/share/containers/storage.conf"
|
||||
]
|
||||
},
|
||||
"filebase": {
|
||||
"type": "string",
|
||||
"description": "Read the base configuration from this file."
|
||||
},
|
||||
"comment": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "storage configuration",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"storage": {
|
||||
"$ref": "#/definitions/storage"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Copy items
|
||||
|
||||
Stage to copy items, that is files or trees, from inputs to mount
|
||||
points or the tree. Multiple items can be copied. The source and
|
||||
destination is an url. Supported locations ('schemes') are `tree`,
|
||||
`mount` and `input`.
|
||||
The path format follows the rsync convention that if the paths
|
||||
ends with a slash `/` the content of that directory is copied not
|
||||
the directory itself.
|
||||
|
||||
Note that the stage by default does not remove the destination
|
||||
before copying. As a result, if the destination is an existing
|
||||
symlink to a file, then this file will be overwritten, instead of
|
||||
the symlink being replaced. If you want to replace the symlink
|
||||
with a file, you need to set the `remove_destination` option to
|
||||
`true`. This option works only for files, not directories or
|
||||
symlinks to directories.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
|
@ -27,79 +7,6 @@ from urllib.parse import ParseResult, urlparse
|
|||
|
||||
import osbuild.api
|
||||
|
||||
CAPABILITIES = ["CAP_MAC_ADMIN"]
|
||||
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["paths"],
|
||||
"properties": {
|
||||
"paths": {
|
||||
"description": "Array of items to copy",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["from", "to"],
|
||||
"properties": {
|
||||
"from": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The source, if an input",
|
||||
"pattern": "^input:\/\/[^\/]+\/"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The source, if a mount",
|
||||
"pattern": "^mount:\/\/[^\/]+\/"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The source, if the tree",
|
||||
"pattern": "^tree:\/\/\/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"to": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The destination, if a mount",
|
||||
"pattern": "^mount:\/\/[^\/]+\/"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The destination, if the tree",
|
||||
"pattern": "^tree:\/\/\/"
|
||||
}
|
||||
]
|
||||
},
|
||||
"remove_destination": {
|
||||
"type": "boolean",
|
||||
"description": "Remove the destination before copying. Works only for files, not directories.",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def parse_mount(url: ParseResult, args: Dict):
|
||||
name = url.netloc
|
||||
|
|
|
|||
96
stages/org.osbuild.copy.meta.json
Normal file
96
stages/org.osbuild.copy.meta.json
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
{
|
||||
"summary": "Copy items",
|
||||
"description": [
|
||||
"Stage to copy items, that is files or trees, from inputs to mount",
|
||||
"points or the tree. Multiple items can be copied. The source and",
|
||||
"destination is an url. Supported locations ('schemes') are `tree`,",
|
||||
"`mount` and `input`.",
|
||||
"The path format follows the rsync convention that if the paths",
|
||||
"ends with a slash `/` the content of that directory is copied not",
|
||||
"the directory itself.",
|
||||
"Note that the stage by default does not remove the destination",
|
||||
"before copying. As a result, if the destination is an existing",
|
||||
"symlink to a file, then this file will be overwritten, instead of",
|
||||
"the symlink being replaced. If you want to replace the symlink",
|
||||
"with a file, you need to set the `remove_destination` option to",
|
||||
"`true`. This option works only for files, not directories or",
|
||||
"symlinks to directories."
|
||||
],
|
||||
"capabilities": [
|
||||
"CAP_MAC_ADMIN"
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"paths"
|
||||
],
|
||||
"properties": {
|
||||
"paths": {
|
||||
"description": "Array of items to copy",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"from",
|
||||
"to"
|
||||
],
|
||||
"properties": {
|
||||
"from": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The source, if an input",
|
||||
"pattern": "^input://[^/]+/"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The source, if a mount",
|
||||
"pattern": "^mount://[^/]+/"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The source, if the tree",
|
||||
"pattern": "^tree:///"
|
||||
}
|
||||
]
|
||||
},
|
||||
"to": {
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The destination, if a mount",
|
||||
"pattern": "^mount://[^/]+/"
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"description": "The destination, if the tree",
|
||||
"pattern": "^tree:///"
|
||||
}
|
||||
]
|
||||
},
|
||||
"remove_destination": {
|
||||
"type": "boolean",
|
||||
"description": "Remove the destination before copying. Works only for files, not directories.",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Setup a CoreOS platform
|
||||
|
||||
In CoreOS we have the concept of a platform (i.e. AWS, GCP, Metal, QEMU)
|
||||
where each platform has its own provided disk image with slightly
|
||||
differing settings/behavior. This stage will perform the necessary
|
||||
configuration for the given platform. This configuration boils down to
|
||||
a few steps:
|
||||
1. Locate the source of platform specific information that is provided
|
||||
in the CoreOS filesystem tree already (the platforms.json).
|
||||
2. Copy the platforms.json file into the /boot/ partition, which is
|
||||
sometimes used by coreos-installer.
|
||||
3. Read the platforms.json to fetch and platform specific kernel
|
||||
arguments or grub configuration to set. These arguments/config
|
||||
are primarily console settings.
|
||||
4. Apply any platform specific kernel arguments along with the
|
||||
`ignition.platform.id={platform-name}` kernel argument.
|
||||
5. Create the grub console.cfg file and apply any platform
|
||||
specific grub console configuration.
|
||||
This stage is highly CoreOS specific and subject to change in the
|
||||
future if/when we change the way platform specific information is
|
||||
defined in our broader efforts to share more defaults with OSBuild.
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import shutil
|
||||
|
|
@ -30,24 +7,6 @@ import sys
|
|||
import osbuild.api
|
||||
from osbuild.util import bls
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"platform": {
|
||||
"description": "The target platform name/ID",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
"""
|
||||
|
||||
# Constants
|
||||
# For console.cfg see https://github.com/coreos/bootupd/pull/620
|
||||
|
|
|
|||
42
stages/org.osbuild.coreos.platform.meta.json
Normal file
42
stages/org.osbuild.coreos.platform.meta.json
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
{
|
||||
"summary": "Setup a CoreOS platform",
|
||||
"description": [
|
||||
"In CoreOS we have the concept of a platform (i.e. AWS, GCP, Metal, QEMU)",
|
||||
"where each platform has its own provided disk image with slightly",
|
||||
"differing settings/behavior. This stage will perform the necessary",
|
||||
"configuration for the given platform. This configuration boils down to",
|
||||
"a few steps:",
|
||||
"1. Locate the source of platform specific information that is provided",
|
||||
" in the CoreOS filesystem tree already (the platforms.json).",
|
||||
"2. Copy the platforms.json file into the /boot/ partition, which is",
|
||||
" sometimes used by coreos-installer.",
|
||||
"3. Read the platforms.json to fetch and platform specific kernel",
|
||||
" arguments or grub configuration to set. These arguments/config",
|
||||
" are primarily console settings.",
|
||||
"4. Apply any platform specific kernel arguments along with the",
|
||||
" `ignition.platform.id={platform-name}` kernel argument.",
|
||||
"5. Create the grub console.cfg file and apply any platform",
|
||||
" specific grub console configuration.",
|
||||
"This stage is highly CoreOS specific and subject to change in the",
|
||||
"future if/when we change the way platform specific information is",
|
||||
"defined in our broader efforts to share more defaults with OSBuild."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"platform": {
|
||||
"description": "The target platform name/ID",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"devices": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
},
|
||||
"mounts": {
|
||||
"type": "array"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Assembles the tree into a CPIO archive.
|
||||
|
||||
Uses the buildhost's `cpio` command, to create an archive
|
||||
at `filename` with the contents of the input `tree`. If
|
||||
`append` is `true`, its files will be added to an existing
|
||||
archive. The default format is `newc` , the "new (SVR4)
|
||||
portable format", which is also used by `dracut`(8).
|
||||
|
||||
Buildhost commands used: `cpio`
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename for tar archive",
|
||||
"type": "string"
|
||||
},
|
||||
"append": {
|
||||
"type": "boolean",
|
||||
"description": "Append to an existing archive.",
|
||||
"default": false
|
||||
},
|
||||
"format": {
|
||||
"description": "Archive format to use",
|
||||
"type": "string",
|
||||
"enum": ["bin", "odc", "newc", "crc", "tar", "ustar"],
|
||||
"default": "newc"
|
||||
},
|
||||
"root-node": {
|
||||
"description": "How to handle the root node: include or omit",
|
||||
"enum": ["include", "omit"],
|
||||
"default": "include"
|
||||
},
|
||||
"reproducible": {
|
||||
"type": "boolean",
|
||||
"description": "Produce device-independent, reproducible archives.",
|
||||
"default": true
|
||||
},
|
||||
"owner": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["user"],
|
||||
"properties": {
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["tree"],
|
||||
"properties": {
|
||||
"tree": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def iter_files(tree, include):
|
||||
for root, _, files in os.walk(tree, topdown=True):
|
||||
|
|
|
|||
84
stages/org.osbuild.cpio.out.meta.json
Normal file
84
stages/org.osbuild.cpio.out.meta.json
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
{
|
||||
"summary": "Assembles the tree into a CPIO archive.",
|
||||
"description": [
|
||||
"Uses the buildhost's `cpio` command, to create an archive",
|
||||
"at `filename` with the contents of the input `tree`. If",
|
||||
"`append` is `true`, its files will be added to an existing",
|
||||
"archive. The default format is `newc` , the \"new (SVR4)",
|
||||
"portable format\", which is also used by `dracut`(8).",
|
||||
"Buildhost commands used: `cpio`"
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"filename"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename for tar archive",
|
||||
"type": "string"
|
||||
},
|
||||
"append": {
|
||||
"type": "boolean",
|
||||
"description": "Append to an existing archive.",
|
||||
"default": false
|
||||
},
|
||||
"format": {
|
||||
"description": "Archive format to use",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"bin",
|
||||
"odc",
|
||||
"newc",
|
||||
"crc",
|
||||
"tar",
|
||||
"ustar"
|
||||
],
|
||||
"default": "newc"
|
||||
},
|
||||
"root-node": {
|
||||
"description": "How to handle the root node: include or omit",
|
||||
"enum": [
|
||||
"include",
|
||||
"omit"
|
||||
],
|
||||
"default": "include"
|
||||
},
|
||||
"reproducible": {
|
||||
"type": "boolean",
|
||||
"description": "Produce device-independent, reproducible archives.",
|
||||
"default": true
|
||||
},
|
||||
"owner": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"user"
|
||||
],
|
||||
"properties": {
|
||||
"user": {
|
||||
"type": "string"
|
||||
},
|
||||
"group": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"tree"
|
||||
],
|
||||
"properties": {
|
||||
"tree": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,59 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Run a script at regular intervals.
|
||||
|
||||
Execute a script at regular intervals. This uses the cron drop-in
|
||||
directories in etc, which correspond to the supported intervals:
|
||||
`cron.hourly/`, `cron.daily/`, `cron.weekly/`, `cron.monthly/`
|
||||
|
||||
NB: Does itself not create the directories so they must be created
|
||||
via the package that provides the facility, like `cronie` or on
|
||||
older systems `crontabs`.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["interval", "filename"],
|
||||
"oneOf": [
|
||||
{"required": ["simple"]}
|
||||
],
|
||||
"properties": {
|
||||
"interval": {
|
||||
"type": "string",
|
||||
"enum": ["hourly", "daily", "weekly", "monthly"]
|
||||
},
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Name of the cron script",
|
||||
"pattern": "^[\\w.-]{1,255}$"
|
||||
},
|
||||
"simple": {
|
||||
"type": "object",
|
||||
"description": "A simple command to run.",
|
||||
"required": ["command"],
|
||||
"properties": {
|
||||
"comment": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def format_comment(comment):
|
||||
lines = comment.split("\n")
|
||||
|
|
|
|||
61
stages/org.osbuild.cron.script.meta.json
Normal file
61
stages/org.osbuild.cron.script.meta.json
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"summary": "Run a script at regular intervals.",
|
||||
"description": [
|
||||
"Execute a script at regular intervals. This uses the cron drop-in",
|
||||
"directories in etc, which correspond to the supported intervals:",
|
||||
" `cron.hourly/`, `cron.daily/`, `cron.weekly/`, `cron.monthly/`",
|
||||
"NB: Does itself not create the directories so they must be created",
|
||||
"via the package that provides the facility, like `cronie` or on",
|
||||
"older systems `crontabs`."
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"interval",
|
||||
"filename"
|
||||
],
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"simple"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"interval": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hourly",
|
||||
"daily",
|
||||
"weekly",
|
||||
"monthly"
|
||||
]
|
||||
},
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Name of the cron script",
|
||||
"pattern": "^[\\w.-]{1,255}$"
|
||||
},
|
||||
"simple": {
|
||||
"type": "object",
|
||||
"description": "A simple command to run.",
|
||||
"required": [
|
||||
"command"
|
||||
],
|
||||
"properties": {
|
||||
"comment": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"command": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,66 +1,8 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create /etc/crypttab entries for encrypted block devices
|
||||
|
||||
See crypttab(5) for a detailed description of the format but in brief:
|
||||
each item in the list of `volumes` describes an encrypted block device
|
||||
and how it should it should be setup. The block device is identified
|
||||
either by `uuid` or by `path` (device node path). The volume will be
|
||||
named as `volume`, i.e. made available as `/dev/mapper/$volume`.
|
||||
Additionally, a keyfile can (optionally) be specified via `keyfile`.
|
||||
Specific device options can be specified via `options`.
|
||||
|
||||
This stage replaces /etc/crypttab, removing any existing entries.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["volumes"],
|
||||
"properties": {
|
||||
"volumes": {
|
||||
"type": "array",
|
||||
"description": "array of volume objects",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"oneOf": [{
|
||||
"required": ["uuid", "volume"]
|
||||
}, {
|
||||
"required": ["path", "volume"]
|
||||
}],
|
||||
"properties": {
|
||||
"volume": {
|
||||
"description": "volume mountpoint",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "device UUID",
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"description": "device path",
|
||||
"type": "string"
|
||||
},
|
||||
"keyfile": {
|
||||
"description": "",
|
||||
"type": "string",
|
||||
"default": "none"
|
||||
},
|
||||
"options": {
|
||||
"description": "options (comma-separated)",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
volumes = options["volumes"]
|
||||
|
|
|
|||
66
stages/org.osbuild.crypttab.meta.json
Normal file
66
stages/org.osbuild.crypttab.meta.json
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
{
|
||||
"summary": "Create /etc/crypttab entries for encrypted block devices",
|
||||
"description": [
|
||||
"See crypttab(5) for a detailed description of the format but in brief:",
|
||||
"each item in the list of `volumes` describes an encrypted block device",
|
||||
"and how it should it should be setup. The block device is identified",
|
||||
"either by `uuid` or by `path` (device node path). The volume will be",
|
||||
"named as `volume`, i.e. made available as `/dev/mapper/$volume`.",
|
||||
"Additionally, a keyfile can (optionally) be specified via `keyfile`.",
|
||||
"Specific device options can be specified via `options`.",
|
||||
"This stage replaces /etc/crypttab, removing any existing entries."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"volumes"
|
||||
],
|
||||
"properties": {
|
||||
"volumes": {
|
||||
"type": "array",
|
||||
"description": "array of volume objects",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"uuid",
|
||||
"volume"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"path",
|
||||
"volume"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"volume": {
|
||||
"description": "volume mountpoint",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "device UUID",
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"description": "device path",
|
||||
"type": "string"
|
||||
},
|
||||
"keyfile": {
|
||||
"description": "",
|
||||
"type": "string",
|
||||
"default": "none"
|
||||
},
|
||||
"options": {
|
||||
"description": "options (comma-separated)",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Set up an early root shell on a certain tty
|
||||
|
||||
Creates a systemd unit file at /etc/systemd/system/osbuild-debug-shell.service
|
||||
which starts an early-boot root shell on the given `tty`.
|
||||
|
||||
Also symlinks the service file into /etc/systemd/system/sysinit.target.wants/.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["tty"],
|
||||
"properties": {
|
||||
"tty": {
|
||||
"type": "string",
|
||||
"description": "Absolute path of the tty device to start a root shell on."
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
tty = options["tty"]
|
||||
|
|
|
|||
20
stages/org.osbuild.debug-shell.meta.json
Normal file
20
stages/org.osbuild.debug-shell.meta.json
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"summary": "Set up an early root shell on a certain tty",
|
||||
"description": [
|
||||
"Creates a systemd unit file at /etc/systemd/system/osbuild-debug-shell.service",
|
||||
"which starts an early-boot root shell on the given `tty`.",
|
||||
"Also symlinks the service file into /etc/systemd/system/sysinit.target.wants/."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"tty"
|
||||
],
|
||||
"properties": {
|
||||
"tty": {
|
||||
"type": "string",
|
||||
"description": "Absolute path of the tty device to start a root shell on."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,31 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create a `.discinfo` file describing disk
|
||||
|
||||
This will create a `.discinfo` file with the specified parameters.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": true,
|
||||
"required": ["basearch", "release"],
|
||||
"properties": {
|
||||
"basearch": {
|
||||
"description": "Build architecture.",
|
||||
"type": "string"
|
||||
},
|
||||
"release": {
|
||||
"description": "The product name.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
basearch = options["basearch"]
|
||||
|
|
|
|||
23
stages/org.osbuild.discinfo.meta.json
Normal file
23
stages/org.osbuild.discinfo.meta.json
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"summary": "Create a `.discinfo` file describing disk",
|
||||
"description": [
|
||||
"This will create a `.discinfo` file with the specified parameters."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": true,
|
||||
"required": [
|
||||
"basearch",
|
||||
"release"
|
||||
],
|
||||
"properties": {
|
||||
"basearch": {
|
||||
"description": "Build architecture.",
|
||||
"type": "string"
|
||||
},
|
||||
"release": {
|
||||
"description": "The product name.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Change DNF Automatic configuration.
|
||||
|
||||
The stage changes persistent DNF Automatic configuration. Currently, only
|
||||
a subset of options can be set:
|
||||
- 'commands' section
|
||||
- apply_updates
|
||||
- upgrade_type
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import iniparse
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"definitions": {
|
||||
"commands": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "'commands' configuration section.",
|
||||
"properties": {
|
||||
"apply_updates": {
|
||||
"type": "boolean",
|
||||
"description": "Whether packages comprising the available updates should be installed."
|
||||
},
|
||||
"upgrade_type": {
|
||||
"type": "string",
|
||||
"description": "What kind of upgrades to look at.",
|
||||
"enum": ["default", "security"]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "DNF Automatic configuration.",
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "configuration definition.",
|
||||
"properties": {
|
||||
"commands": {
|
||||
"$ref": "#/definitions/commands"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def bool_to_yes_no(b):
|
||||
if b:
|
||||
|
|
|
|||
47
stages/org.osbuild.dnf-automatic.config.meta.json
Normal file
47
stages/org.osbuild.dnf-automatic.config.meta.json
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
{
|
||||
"summary": "Change DNF Automatic configuration.",
|
||||
"description": [
|
||||
"The stage changes persistent DNF Automatic configuration. Currently, only",
|
||||
"a subset of options can be set:",
|
||||
" - 'commands' section",
|
||||
" - apply_updates",
|
||||
" - upgrade_type"
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"commands": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "'commands' configuration section.",
|
||||
"properties": {
|
||||
"apply_updates": {
|
||||
"type": "boolean",
|
||||
"description": "Whether packages comprising the available updates should be installed."
|
||||
},
|
||||
"upgrade_type": {
|
||||
"type": "string",
|
||||
"description": "What kind of upgrades to look at.",
|
||||
"enum": [
|
||||
"default",
|
||||
"security"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "DNF Automatic configuration.",
|
||||
"properties": {
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "configuration definition.",
|
||||
"properties": {
|
||||
"commands": {
|
||||
"$ref": "#/definitions/commands"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Change DNF configuration.
|
||||
|
||||
The stage changes persistent DNF configuration on the filesystem.
|
||||
|
||||
Allows defining dnf variables via the `variables` option and
|
||||
specific configuration options via the `config` option. The
|
||||
latter will be saved in `/etc/dnf/dnf.conf`. See `dnf.conf(5)`
|
||||
for details about the configuration options.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
|
@ -17,79 +6,6 @@ import iniparse
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"definitions": {
|
||||
"variable": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "value"],
|
||||
"description": "DNF variable to configure persistently.",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9_]+$",
|
||||
"description": "Name of the variable."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the variable."
|
||||
}
|
||||
}
|
||||
},
|
||||
"config_main": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ip_resolve": {
|
||||
"type": "string",
|
||||
"enum": ["4", "IPv4", "6", "IPv6"],
|
||||
"description": "Determines how DNF resolves host names."
|
||||
},
|
||||
"tsflags": {
|
||||
"type": "array",
|
||||
"description": "Extra flags for the RPM transaction.",
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"noscripts",
|
||||
"test",
|
||||
"notriggers",
|
||||
"nodocs",
|
||||
"justdb",
|
||||
"nocontexts",
|
||||
"nocaps",
|
||||
"nocrypto"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "DNF configuration.",
|
||||
"properties": {
|
||||
"variables": {
|
||||
"type": "array",
|
||||
"description": "DNF variables to configure persistently.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/variable"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "DNF global configuration.",
|
||||
"properties": {
|
||||
"main": {
|
||||
"$ref": "#/definitions/config_main"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def configure_variable(tree, name, value):
|
||||
"""
|
||||
|
|
|
|||
90
stages/org.osbuild.dnf.config.meta.json
Normal file
90
stages/org.osbuild.dnf.config.meta.json
Normal file
|
|
@ -0,0 +1,90 @@
|
|||
{
|
||||
"summary": "Change DNF configuration.",
|
||||
"description": [
|
||||
"The stage changes persistent DNF configuration on the filesystem.",
|
||||
"Allows defining dnf variables via the `variables` option and",
|
||||
"specific configuration options via the `config` option. The",
|
||||
"latter will be saved in `/etc/dnf/dnf.conf`. See `dnf.conf(5)`",
|
||||
"for details about the configuration options."
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"variable": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"value"
|
||||
],
|
||||
"description": "DNF variable to configure persistently.",
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"pattern": "^[a-z0-9_]+$",
|
||||
"description": "Name of the variable."
|
||||
},
|
||||
"value": {
|
||||
"type": "string",
|
||||
"description": "Value of the variable."
|
||||
}
|
||||
}
|
||||
},
|
||||
"config_main": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ip_resolve": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"4",
|
||||
"IPv4",
|
||||
"6",
|
||||
"IPv6"
|
||||
],
|
||||
"description": "Determines how DNF resolves host names."
|
||||
},
|
||||
"tsflags": {
|
||||
"type": "array",
|
||||
"description": "Extra flags for the RPM transaction.",
|
||||
"minItems": 1,
|
||||
"uniqueItems": true,
|
||||
"items": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"noscripts",
|
||||
"test",
|
||||
"notriggers",
|
||||
"nodocs",
|
||||
"justdb",
|
||||
"nocontexts",
|
||||
"nocaps",
|
||||
"nocrypto"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"description": "DNF configuration.",
|
||||
"properties": {
|
||||
"variables": {
|
||||
"type": "array",
|
||||
"description": "DNF variables to configure persistently.",
|
||||
"items": {
|
||||
"$ref": "#/definitions/variable"
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "DNF global configuration.",
|
||||
"properties": {
|
||||
"main": {
|
||||
"$ref": "#/definitions/config_main"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Mark packages in the DNF state database.
|
||||
"""
|
||||
|
||||
import shutil
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
from osbuild import api
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"packages": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "Packages and their marks.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "mark"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Package name."
|
||||
},
|
||||
"mark": {
|
||||
"type": "string",
|
||||
"enum": ["install", "group"],
|
||||
"description": "Package mark."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def mark(tree, packages):
|
||||
dnf_bin = shutil.which("dnf-3")
|
||||
|
|
|
|||
38
stages/org.osbuild.dnf4.mark.meta.json
Normal file
38
stages/org.osbuild.dnf4.mark.meta.json
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
{
|
||||
"summary": "Mark packages in the DNF state database.",
|
||||
"description": [],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"packages": {
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"description": "Packages and their marks.",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"mark"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "Package name."
|
||||
},
|
||||
"mark": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"install",
|
||||
"group"
|
||||
],
|
||||
"description": "Package mark."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,141 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create (re-create) the initial RAM file-system
|
||||
|
||||
Uses `dracut` to re-create the initial RAM filesystem, see man dracut(8).
|
||||
The kernels for which the initramfs should be generated need to be provided
|
||||
via `kernel` matching their name on the disk, like "5.6.6-300.fc32.x86_64".
|
||||
|
||||
Supports most options also found in `dracut`(8). See the respective man
|
||||
page and schema for this stage.
|
||||
|
||||
NB: needs chroot for now as well as `strip` for stripping the initrfams.
|
||||
"""
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"required": ["kernel"],
|
||||
"properties": {
|
||||
"kernel": {
|
||||
"description": "List of target kernel versions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel version"
|
||||
}
|
||||
},
|
||||
"compress": {
|
||||
"description": "Compress the initramfs, passed via `--compress`",
|
||||
"type": "string"
|
||||
},
|
||||
"modules": {
|
||||
"description": "Exact list of dracut modules to use.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"add_modules": {
|
||||
"description": "Additional dracut modules to include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"omit_modules": {
|
||||
"description": "Dracut modules to not include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"drivers": {
|
||||
"description": "Kernel modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"add_drivers": {
|
||||
"description": "Add a specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"omit_drivers": {
|
||||
"description": "Omit specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"force_drivers": {
|
||||
"description": "Add driver and ensure that they are tried to be loaded.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"filesystems": {
|
||||
"description": "Kernel filesystem modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"include": {
|
||||
"description": "Add custom files to the initramfs.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "What (keys) to include where (values)"
|
||||
}
|
||||
},
|
||||
"install": {
|
||||
"description": "Install the specified files.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"early_microcode": {
|
||||
"description": "Combine early microcode with the initramfs.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"reproducible": {
|
||||
"description": "Create reproducible images.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"initoverlayfs": {
|
||||
"description": "Use initoverlayfs rather than initramfs, requires initoverlayfs rpm to be installed",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"extra": {
|
||||
"description": "Extra arguments to directly pass to dracut",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Individual extra arguments"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def yesno(name: str, value: bool) -> str:
|
||||
prefix = "" if value else "no-"
|
||||
|
|
|
|||
|
|
@ -1,138 +1,8 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure dracut.
|
||||
|
||||
The 'config' option allows to create a dracut configuration file under
|
||||
`/usr/lib/dracut/dracut.conf.d/` with the name `filename`. Only a subset
|
||||
of configuration options is supported, with the intention to provide
|
||||
functional parity with `org.osbuild.dracut` stage.
|
||||
|
||||
Constrains:
|
||||
- At least one configuration option must be specified for each configuration
|
||||
|
||||
Supported configuration options:
|
||||
- compress
|
||||
- dracutmodules
|
||||
- add_dracutmodules
|
||||
- omit_dracutmodules
|
||||
- drivers
|
||||
- add_drivers
|
||||
- omit_drivers
|
||||
- force_drivers
|
||||
- filesystems
|
||||
- install_items
|
||||
- early_microcode
|
||||
- reproducible
|
||||
"""
|
||||
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"additionalProperties": false,
|
||||
"required": ["config", "filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Name of the dracut configuration file.",
|
||||
"pattern": "^[\\w.-]{1,250}\\.conf$"
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "dracut configuration.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"compress": {
|
||||
"description": "Compress the generated initramfs using the passed compression program.",
|
||||
"type": "string"
|
||||
},
|
||||
"dracutmodules": {
|
||||
"description": "Exact list of dracut modules to use.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"add_dracutmodules": {
|
||||
"description": "Additional dracut modules to include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"omit_dracutmodules": {
|
||||
"description": "Dracut modules to not include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"drivers": {
|
||||
"description": "Kernel modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"add_drivers": {
|
||||
"description": "Add a specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"omit_drivers": {
|
||||
"description": "Omit specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"force_drivers": {
|
||||
"description": "Add driver and ensure that they are tried to be loaded.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"filesystems": {
|
||||
"description": "Kernel filesystem modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"install_items": {
|
||||
"description": "Install the specified files.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Specify additional files to include in the initramfs."
|
||||
}
|
||||
},
|
||||
"early_microcode": {
|
||||
"description": "Combine early microcode with the initramfs.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"reproducible": {
|
||||
"description": "Create reproducible images.",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def bool_to_string(value):
|
||||
return "yes" if value else "no"
|
||||
|
|
|
|||
130
stages/org.osbuild.dracut.conf.meta.json
Normal file
130
stages/org.osbuild.dracut.conf.meta.json
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
{
|
||||
"summary": "Configure dracut.",
|
||||
"description": [
|
||||
"The 'config' option allows to create a dracut configuration file under",
|
||||
"`/usr/lib/dracut/dracut.conf.d/` with the name `filename`. Only a subset",
|
||||
"of configuration options is supported, with the intention to provide",
|
||||
"functional parity with `org.osbuild.dracut` stage.",
|
||||
"Constrains:",
|
||||
" - At least one configuration option must be specified for each configuration",
|
||||
"Supported configuration options:",
|
||||
" - compress",
|
||||
" - dracutmodules",
|
||||
" - add_dracutmodules",
|
||||
" - omit_dracutmodules",
|
||||
" - drivers",
|
||||
" - add_drivers",
|
||||
" - omit_drivers",
|
||||
" - force_drivers",
|
||||
" - filesystems",
|
||||
" - install_items",
|
||||
" - early_microcode",
|
||||
" - reproducible"
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"config",
|
||||
"filename"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Name of the dracut configuration file.",
|
||||
"pattern": "^[\\w.-]{1,250}\\.conf$"
|
||||
},
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "dracut configuration.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"compress": {
|
||||
"description": "Compress the generated initramfs using the passed compression program.",
|
||||
"type": "string"
|
||||
},
|
||||
"dracutmodules": {
|
||||
"description": "Exact list of dracut modules to use.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"add_dracutmodules": {
|
||||
"description": "Additional dracut modules to include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"omit_dracutmodules": {
|
||||
"description": "Dracut modules to not include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"drivers": {
|
||||
"description": "Kernel modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"add_drivers": {
|
||||
"description": "Add a specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"omit_drivers": {
|
||||
"description": "Omit specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"force_drivers": {
|
||||
"description": "Add driver and ensure that they are tried to be loaded.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"filesystems": {
|
||||
"description": "Kernel filesystem modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"install_items": {
|
||||
"description": "Install the specified files.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Specify additional files to include in the initramfs."
|
||||
}
|
||||
},
|
||||
"early_microcode": {
|
||||
"description": "Combine early microcode with the initramfs.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"reproducible": {
|
||||
"description": "Create reproducible images.",
|
||||
"type": "boolean"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
131
stages/org.osbuild.dracut.meta.json
Normal file
131
stages/org.osbuild.dracut.meta.json
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
{
|
||||
"summary": "Create (re-create) the initial RAM file-system",
|
||||
"description": [
|
||||
"Uses `dracut` to re-create the initial RAM filesystem, see man dracut(8).",
|
||||
"The kernels for which the initramfs should be generated need to be provided",
|
||||
"via `kernel` matching their name on the disk, like \"5.6.6-300.fc32.x86_64\".",
|
||||
"Supports most options also found in `dracut`(8). See the respective man",
|
||||
"page and schema for this stage.",
|
||||
"NB: needs chroot for now as well as `strip` for stripping the initrfams."
|
||||
],
|
||||
"schema": {
|
||||
"required": [
|
||||
"kernel"
|
||||
],
|
||||
"properties": {
|
||||
"kernel": {
|
||||
"description": "List of target kernel versions",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel version"
|
||||
}
|
||||
},
|
||||
"compress": {
|
||||
"description": "Compress the initramfs, passed via `--compress`",
|
||||
"type": "string"
|
||||
},
|
||||
"modules": {
|
||||
"description": "Exact list of dracut modules to use.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"add_modules": {
|
||||
"description": "Additional dracut modules to include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"omit_modules": {
|
||||
"description": "Dracut modules to not include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A dracut module, e.g. base, nfs, network ..."
|
||||
}
|
||||
},
|
||||
"drivers": {
|
||||
"description": "Kernel modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"add_drivers": {
|
||||
"description": "Add a specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"omit_drivers": {
|
||||
"description": "Omit specific kernel modules.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension."
|
||||
}
|
||||
},
|
||||
"force_drivers": {
|
||||
"description": "Add driver and ensure that they are tried to be loaded.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"filesystems": {
|
||||
"description": "Kernel filesystem modules to exclusively include.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A kernel module without the .ko extension"
|
||||
}
|
||||
},
|
||||
"include": {
|
||||
"description": "Add custom files to the initramfs.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"description": "What (keys) to include where (values)"
|
||||
}
|
||||
},
|
||||
"install": {
|
||||
"description": "Install the specified files.",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"early_microcode": {
|
||||
"description": "Combine early microcode with the initramfs.",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"reproducible": {
|
||||
"description": "Create reproducible images.",
|
||||
"type": "boolean"
|
||||
},
|
||||
"initoverlayfs": {
|
||||
"description": "Use initoverlayfs rather than initramfs, requires initoverlayfs rpm to be installed",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"extra": {
|
||||
"description": "Extra arguments to directly pass to dracut",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Individual extra arguments"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,76 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create a file containing an erofs filesystem named `filename`.
|
||||
|
||||
See https://en.wikipedia.org/wiki/EROFS for details about the
|
||||
filesystem.
|
||||
|
||||
Buildhost commands used: `mkfs.erofs`
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename for the output",
|
||||
"type": "string"
|
||||
},
|
||||
"compression": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["method"],
|
||||
"properties": {
|
||||
"method": {
|
||||
"description": "Compression method",
|
||||
"enum": ["lz4", "lz4hc", "lzma"]
|
||||
},
|
||||
"level": {
|
||||
"description": "Compression level. Note that different methods support different levels. See mkfs.erofs(1) for more details",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"description": "Extended options for the filesystem, see mkfs.erofs(1)",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items:": {
|
||||
"enum": [
|
||||
"all-fragments",
|
||||
"dedupe",
|
||||
"force-inode-compact",
|
||||
"force-inode-extended",
|
||||
"force-inode-blockmap",
|
||||
"force-chunk-indexes",
|
||||
"fragments",
|
||||
"noinline_data",
|
||||
"ztailpacking"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["tree"],
|
||||
"properties": {
|
||||
"tree": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(inputs, output_dir, options):
|
||||
source = inputs["tree"]["path"]
|
||||
|
|
|
|||
74
stages/org.osbuild.erofs.meta.json
Normal file
74
stages/org.osbuild.erofs.meta.json
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
{
|
||||
"summary": "Create a file containing an erofs filesystem named `filename`.",
|
||||
"description": [
|
||||
"See https://en.wikipedia.org/wiki/EROFS for details about the",
|
||||
"filesystem.",
|
||||
"Buildhost commands used: `mkfs.erofs`"
|
||||
],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"filename"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename for the output",
|
||||
"type": "string"
|
||||
},
|
||||
"compression": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"method"
|
||||
],
|
||||
"properties": {
|
||||
"method": {
|
||||
"description": "Compression method",
|
||||
"enum": [
|
||||
"lz4",
|
||||
"lz4hc",
|
||||
"lzma"
|
||||
]
|
||||
},
|
||||
"level": {
|
||||
"description": "Compression level. Note that different methods support different levels. See mkfs.erofs(1) for more details",
|
||||
"type": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"description": "Extended options for the filesystem, see mkfs.erofs(1)",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items:": {
|
||||
"enum": [
|
||||
"all-fragments",
|
||||
"dedupe",
|
||||
"force-inode-compact",
|
||||
"force-inode-extended",
|
||||
"force-inode-blockmap",
|
||||
"force-chunk-indexes",
|
||||
"fragments",
|
||||
"noinline_data",
|
||||
"ztailpacking"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"tree"
|
||||
],
|
||||
"properties": {
|
||||
"tree": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,27 +1,8 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Return an error
|
||||
|
||||
Error stage. Return the given error. Useful for testing, debugging, and
|
||||
wasting time.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"returncode": {
|
||||
"description": "What to return code to use",
|
||||
"type": "number",
|
||||
"default": 255
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(_tree, options):
|
||||
errno = options.get("returncode", 255)
|
||||
|
|
|
|||
17
stages/org.osbuild.error.meta.json
Normal file
17
stages/org.osbuild.error.meta.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"summary": "Return an error",
|
||||
"description": [
|
||||
"Error stage. Return the given error. Useful for testing, debugging, and",
|
||||
"wasting time."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"returncode": {
|
||||
"description": "What to return code to use",
|
||||
"type": "number",
|
||||
"default": 255
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Change OSTree configuration experimental options
|
||||
|
||||
NOTE: This stage is experimental and subject to changes
|
||||
|
||||
Change the configuration for an OSTree repository.
|
||||
Currently only the following values are supported:
|
||||
- `integrity.composefs`
|
||||
|
||||
See `ostree.repo-config(5)` for more information.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
from osbuild.util import ostree
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["repo"],
|
||||
"properties": {
|
||||
"repo": {
|
||||
"description": "Location of the OSTree repo.",
|
||||
"type": "string"
|
||||
},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "OSTree configuration groups",
|
||||
"properties": {
|
||||
"integrity": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Options concerning the sysroot",
|
||||
"properties": {
|
||||
"composefs": {
|
||||
"description": "Enable composefs image generation on deploy.",
|
||||
"type": "string",
|
||||
"enum": ["true", "false", "maybe"]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
repo = os.path.join(tree, options["repo"].lstrip("/"))
|
||||
|
|
|
|||
45
stages/org.osbuild.experimental.ostree.config.meta.json
Normal file
45
stages/org.osbuild.experimental.ostree.config.meta.json
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"summary": "Change OSTree configuration experimental options",
|
||||
"description": [
|
||||
"NOTE: This stage is experimental and subject to changes",
|
||||
"Change the configuration for an OSTree repository.",
|
||||
"Currently only the following values are supported:",
|
||||
" - `integrity.composefs`",
|
||||
"See `ostree.repo-config(5)` for more information."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"repo"
|
||||
],
|
||||
"properties": {
|
||||
"repo": {
|
||||
"description": "Location of the OSTree repo.",
|
||||
"type": "string"
|
||||
},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "OSTree configuration groups",
|
||||
"properties": {
|
||||
"integrity": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Options concerning the sysroot",
|
||||
"properties": {
|
||||
"composefs": {
|
||||
"description": "Enable composefs image generation on deploy.",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"true",
|
||||
"false",
|
||||
"maybe"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
FDO initial DIUN certificates
|
||||
|
||||
FDO stage to write down the initial DIUN pub key root certificates
|
||||
to be read by the manufacturer client
|
||||
|
||||
This will create a '/fdo_diun_root_certs.pem' with content
|
||||
specified via the `rootcerts` input.
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["rootcerts"],
|
||||
"properties": {
|
||||
"rootcerts": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def parse_input(inputs):
|
||||
image = inputs["rootcerts"]
|
||||
|
|
|
|||
27
stages/org.osbuild.fdo.meta.json
Normal file
27
stages/org.osbuild.fdo.meta.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"summary": "FDO initial DIUN certificates",
|
||||
"description": [
|
||||
"FDO stage to write down the initial DIUN pub key root certificates",
|
||||
"to be read by the manufacturer client",
|
||||
"This will create a '/fdo_diun_root_certs.pem' with content",
|
||||
"specified via the `rootcerts` input."
|
||||
],
|
||||
"schema_2": {
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"rootcerts"
|
||||
],
|
||||
"properties": {
|
||||
"rootcerts": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure firewall
|
||||
|
||||
Configure firewalld using the `firewall-offline-cmd` from inside the target.
|
||||
|
||||
This stage adds each of the given `ports` and `enabled_services` to the default
|
||||
firewall zone using the `--port` and `--service` options, then removes the
|
||||
services listed in `disabled_services` with `--remove-service`.
|
||||
|
||||
Ports should be specified as "portid:protocol" or "portid-portid:protocol",
|
||||
where "portid" is a number (or a port name from `/etc/services`, like "ssh" or
|
||||
"echo") and "protocol" is one of "tcp", "udp", "sctp", or "dccp".
|
||||
|
||||
Enabling or disabling a service that is already enabled or disabled will not
|
||||
cause an error.
|
||||
|
||||
Attempting to enable/disable an unknown service name will cause this stage to
|
||||
fail. Known service names are determined by the contents of firewalld's
|
||||
configuration directories, usually `/{lib,etc}/firewalld/services/*.xml`, and
|
||||
may vary from release to release.
|
||||
|
||||
WARNING: this stage uses `chroot` to run `firewall-offline-cmd` inside the
|
||||
target tree, which means it may fail unexpectedly when the buildhost and target
|
||||
are different arches or OSes.
|
||||
"""
|
||||
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ports": {
|
||||
"description": "Ports (or port ranges) to open",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A port or port range: 'portid[-portid]:protocol'",
|
||||
"pattern": ".:(tcp|udp|sctp|dccp)$"
|
||||
}
|
||||
},
|
||||
"enabled_services": {
|
||||
"description": "Network services to allow in the default firewall zone",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Service name (from /{lib,etc}/firewalld/services/*.xml)"
|
||||
}
|
||||
},
|
||||
"disabled_services": {
|
||||
"description": "Network services to remove from the default firewall zone",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Service name (from /{lib,etc}/firewalld/services/*.xml)"
|
||||
}
|
||||
},
|
||||
"default_zone": {
|
||||
"description": "Set default zone for connections and interfaces where no zone has been selected.",
|
||||
"type": "string"
|
||||
},
|
||||
"zones": {
|
||||
"description": "Bind a list of network sources to a zone to restrict traffic from those sources based on the settings of the zone.",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "configuration for each zone",
|
||||
"required": ["name", "sources"],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "name of the zone, if left empty the sources will apply to the default zone.",
|
||||
"pattern": "^[a-zA-Z0-9_-]+$"
|
||||
},
|
||||
"sources": {
|
||||
"type": "array",
|
||||
"description": "list of sources for the zone",
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"type": "string",
|
||||
"description": "A source: <source>[/<mask>]|<MAC>|ipset:<ipset>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
# Takes a list of <port|application protocol>:<transport protocol> pairs
|
||||
|
|
|
|||
85
stages/org.osbuild.firewall.meta.json
Normal file
85
stages/org.osbuild.firewall.meta.json
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
{
|
||||
"summary": "Configure firewall",
|
||||
"description": [
|
||||
"Configure firewalld using the `firewall-offline-cmd` from inside the target.",
|
||||
"This stage adds each of the given `ports` and `enabled_services` to the default",
|
||||
"firewall zone using the `--port` and `--service` options, then removes the",
|
||||
"services listed in `disabled_services` with `--remove-service`.",
|
||||
"Ports should be specified as \"portid:protocol\" or \"portid-portid:protocol\",",
|
||||
"where \"portid\" is a number (or a port name from `/etc/services`, like \"ssh\" or",
|
||||
"\"echo\") and \"protocol\" is one of \"tcp\", \"udp\", \"sctp\", or \"dccp\".",
|
||||
"Enabling or disabling a service that is already enabled or disabled will not",
|
||||
"cause an error.",
|
||||
"Attempting to enable/disable an unknown service name will cause this stage to",
|
||||
"fail. Known service names are determined by the contents of firewalld's",
|
||||
"configuration directories, usually `/{lib,etc}/firewalld/services/*.xml`, and",
|
||||
"may vary from release to release.",
|
||||
"WARNING: this stage uses `chroot` to run `firewall-offline-cmd` inside the",
|
||||
"target tree, which means it may fail unexpectedly when the buildhost and target",
|
||||
"are different arches or OSes."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"ports": {
|
||||
"description": "Ports (or port ranges) to open",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "A port or port range: 'portid[-portid]:protocol'",
|
||||
"pattern": ".:(tcp|udp|sctp|dccp)$"
|
||||
}
|
||||
},
|
||||
"enabled_services": {
|
||||
"description": "Network services to allow in the default firewall zone",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Service name (from /{lib,etc}/firewalld/services/*.xml)"
|
||||
}
|
||||
},
|
||||
"disabled_services": {
|
||||
"description": "Network services to remove from the default firewall zone",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string",
|
||||
"description": "Service name (from /{lib,etc}/firewalld/services/*.xml)"
|
||||
}
|
||||
},
|
||||
"default_zone": {
|
||||
"description": "Set default zone for connections and interfaces where no zone has been selected.",
|
||||
"type": "string"
|
||||
},
|
||||
"zones": {
|
||||
"description": "Bind a list of network sources to a zone to restrict traffic from those sources based on the settings of the zone.",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"type": "object",
|
||||
"description": "configuration for each zone",
|
||||
"required": [
|
||||
"name",
|
||||
"sources"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string",
|
||||
"description": "name of the zone, if left empty the sources will apply to the default zone.",
|
||||
"pattern": "^[a-zA-Z0-9_-]+$"
|
||||
},
|
||||
"sources": {
|
||||
"type": "array",
|
||||
"description": "list of sources for the zone",
|
||||
"items": {
|
||||
"additionalProperties": false,
|
||||
"type": "string",
|
||||
"description": "A source: <source>[/<mask>]|<MAC>|ipset:<ipset>"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Execute commands on first-boot
|
||||
|
||||
Sequentially execute a list of commands on first-boot / instantiation.
|
||||
|
||||
This stage uses a logic similar to systemd's first-boot to execute a given
|
||||
script only the first time the image is booted.
|
||||
|
||||
An empty flag file /etc/osbuild-first-boot is written to /etc and a systemd
|
||||
service is enabled that is only run when the file exits, and will remove it
|
||||
before executing the given commands.
|
||||
|
||||
If the flag-file cannot be removed, the service fails without executing
|
||||
any further first-boot commands.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["commands"],
|
||||
"properties": {
|
||||
"commands": {
|
||||
"type": "array",
|
||||
"description": "The command lines to execute",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"wait_for_network": {
|
||||
"type": "boolean",
|
||||
"description": "Wait for the network to be up before executing",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def add_first_boot(tree, commands, wait_for_network):
|
||||
if wait_for_network:
|
||||
|
|
|
|||
33
stages/org.osbuild.first-boot.meta.json
Normal file
33
stages/org.osbuild.first-boot.meta.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"summary": "Execute commands on first-boot",
|
||||
"description": [
|
||||
"Sequentially execute a list of commands on first-boot / instantiation.",
|
||||
"This stage uses a logic similar to systemd's first-boot to execute a given",
|
||||
"script only the first time the image is booted.",
|
||||
"An empty flag file /etc/osbuild-first-boot is written to /etc and a systemd",
|
||||
"service is enabled that is only run when the file exits, and will remove it",
|
||||
"before executing the given commands.",
|
||||
"If the flag-file cannot be removed, the service fails without executing",
|
||||
"any further first-boot commands."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"commands"
|
||||
],
|
||||
"properties": {
|
||||
"commands": {
|
||||
"type": "array",
|
||||
"description": "The command lines to execute",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"wait_for_network": {
|
||||
"type": "boolean",
|
||||
"description": "Wait for the network to be up before executing",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Fix paths in /boot/loader/entries
|
||||
|
||||
Fixes paths in /boot/loader/entries that have incorrect paths for /boot.
|
||||
|
||||
This happens because some boot loader config tools (e.g. grub2-mkrelpath)
|
||||
examine /proc/self/mountinfo to find the "real" path to /boot, and find the
|
||||
path to the osbuild tree - which won't be valid at boot time for this image.
|
||||
|
||||
The paths in the Bootloader Specification are relative to the partition
|
||||
they are located on, i.e. `/boot/loader/...` if `/boot` is on the root
|
||||
file-system partition. If `/boot` is on a separate partition, the correct
|
||||
path would be `/loader/.../` The `prefix` can be used to adjust for that.
|
||||
By default it is `/boot`, i.e. assumes `/boot` is on the root file-system.
|
||||
|
||||
This stage reads and (re)writes all .conf files in /boot/loader/entries.
|
||||
"""
|
||||
|
||||
|
||||
import glob
|
||||
import re
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"prefix": {
|
||||
"description": "Prefix to use, normally `/boot`",
|
||||
"type": "string",
|
||||
"default": "/boot"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
"""Fix broken paths in /boot/loader/entries.
|
||||
|
|
|
|||
25
stages/org.osbuild.fix-bls.meta.json
Normal file
25
stages/org.osbuild.fix-bls.meta.json
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"summary": "Fix paths in /boot/loader/entries",
|
||||
"description": [
|
||||
"Fixes paths in /boot/loader/entries that have incorrect paths for /boot.",
|
||||
"This happens because some boot loader config tools (e.g. grub2-mkrelpath)",
|
||||
"examine /proc/self/mountinfo to find the \"real\" path to /boot, and find the",
|
||||
"path to the osbuild tree - which won't be valid at boot time for this image.",
|
||||
"The paths in the Bootloader Specification are relative to the partition",
|
||||
"they are located on, i.e. `/boot/loader/...` if `/boot` is on the root",
|
||||
"file-system partition. If `/boot` is on a separate partition, the correct",
|
||||
"path would be `/loader/.../` The `prefix` can be used to adjust for that.",
|
||||
"By default it is `/boot`, i.e. assumes `/boot` is on the root file-system.",
|
||||
"This stage reads and (re)writes all .conf files in /boot/loader/entries."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"prefix": {
|
||||
"description": "Prefix to use, normally `/boot`",
|
||||
"type": "string",
|
||||
"default": "/boot"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,138 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create /etc/fstab entries for filesystems
|
||||
|
||||
Each filesystem item must have at least the fs_spec, i.e `uuid`,
|
||||
`label`, `partlabel` or `device` and a `path` (mount point).
|
||||
|
||||
This stage replaces /etc/fstab, removing any existing entries.
|
||||
|
||||
NB: The ostree configuration options are experimental and might
|
||||
be replaced with a different mechanism in the near future.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
from osbuild.util import ostree
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["filesystems"],
|
||||
"properties": {
|
||||
"ostree": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["deployment"],
|
||||
"properties": {
|
||||
"deployment": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"default": {"enum": [false]}
|
||||
},
|
||||
"required": ["osname", "ref"]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"default": {"enum": [true]}
|
||||
},
|
||||
"not": {
|
||||
"anyOf": [
|
||||
{"required": ["osname"]},
|
||||
{"required": ["ref"]},
|
||||
{"required": ["serial"]}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"osname": {
|
||||
"description": "Name of the stateroot to be used in the deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"description": "OStree ref to create and use for deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The deployment serial (usually '0')",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"default": {
|
||||
"description": "Find and use the default ostree deployment",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"filesystems": {
|
||||
"type": "array",
|
||||
"description": "array of filesystem objects",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"oneOf": [{
|
||||
"required": ["device", "path"]
|
||||
}, {
|
||||
"required": ["uuid", "path"]
|
||||
}, {
|
||||
"required": ["label", "path"]
|
||||
}, {
|
||||
"required": ["partlabel", "path"]
|
||||
}],
|
||||
"properties": {
|
||||
"device": {
|
||||
"description": "Device node",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "Filesystem UUID",
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"description": "Filesystem label",
|
||||
"type": "string"
|
||||
},
|
||||
"partlabel": {
|
||||
"description": "Partition label.",
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"description": "Filesystem mountpoint",
|
||||
"type": "string"
|
||||
},
|
||||
"vfs_type": {
|
||||
"description": "Filesystem type",
|
||||
"type": "string",
|
||||
"default": "none"
|
||||
},
|
||||
"options": {
|
||||
"description": "Filesystem options (comma-separated)",
|
||||
"type": "string",
|
||||
"default": "defaults"
|
||||
},
|
||||
"freq": {
|
||||
"description": "dump(8) period in days",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"passno": {
|
||||
"description": "pass number on parallel fsck(8)",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
filesystems = options["filesystems"]
|
||||
|
|
|
|||
169
stages/org.osbuild.fstab.meta.json
Normal file
169
stages/org.osbuild.fstab.meta.json
Normal file
|
|
@ -0,0 +1,169 @@
|
|||
{
|
||||
"summary": "Create /etc/fstab entries for filesystems",
|
||||
"description": [
|
||||
"Each filesystem item must have at least the fs_spec, i.e `uuid`,",
|
||||
"`label`, `partlabel` or `device` and a `path` (mount point).",
|
||||
"This stage replaces /etc/fstab, removing any existing entries.",
|
||||
"NB: The ostree configuration options are experimental and might",
|
||||
"be replaced with a different mechanism in the near future."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"filesystems"
|
||||
],
|
||||
"properties": {
|
||||
"ostree": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"deployment"
|
||||
],
|
||||
"properties": {
|
||||
"deployment": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{
|
||||
"properties": {
|
||||
"default": {
|
||||
"enum": [
|
||||
false
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"osname",
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
{
|
||||
"properties": {
|
||||
"default": {
|
||||
"enum": [
|
||||
true
|
||||
]
|
||||
}
|
||||
},
|
||||
"not": {
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"osname"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"ref"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"serial"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"osname": {
|
||||
"description": "Name of the stateroot to be used in the deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"ref": {
|
||||
"description": "OStree ref to create and use for deployment",
|
||||
"type": "string"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The deployment serial (usually '0')",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"default": {
|
||||
"description": "Find and use the default ostree deployment",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"filesystems": {
|
||||
"type": "array",
|
||||
"description": "array of filesystem objects",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"device",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"uuid",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"label",
|
||||
"path"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"partlabel",
|
||||
"path"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"device": {
|
||||
"description": "Device node",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "Filesystem UUID",
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"description": "Filesystem label",
|
||||
"type": "string"
|
||||
},
|
||||
"partlabel": {
|
||||
"description": "Partition label.",
|
||||
"type": "string"
|
||||
},
|
||||
"path": {
|
||||
"description": "Filesystem mountpoint",
|
||||
"type": "string"
|
||||
},
|
||||
"vfs_type": {
|
||||
"description": "Filesystem type",
|
||||
"type": "string",
|
||||
"default": "none"
|
||||
},
|
||||
"options": {
|
||||
"description": "Filesystem options (comma-separated)",
|
||||
"type": "string",
|
||||
"default": "defaults"
|
||||
},
|
||||
"freq": {
|
||||
"description": "dump(8) period in days",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
},
|
||||
"passno": {
|
||||
"description": "pass number on parallel fsck(8)",
|
||||
"type": "number",
|
||||
"default": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,16 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create or modify the GCP guest-agent config
|
||||
|
||||
Create or modify the GCP guest-agent config, depending on the
|
||||
scope either at:
|
||||
/etc/default/instance_configs.cfg.distro or
|
||||
/etc/default/instance_configs.cfg
|
||||
|
||||
Configuration sections and options may contain any of these values:
|
||||
https://github.com/GoogleCloudPlatform/guest-agent#configuration
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
|
||||
|
|
@ -18,204 +6,6 @@ import iniparse
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"definitions": {
|
||||
"Accounts": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Accounts section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"deprovision_remove": {
|
||||
"type": "boolean",
|
||||
"description": "Makes deprovisioning a user destructive."
|
||||
},
|
||||
"groups": {
|
||||
"type": "array",
|
||||
"description": "List of groups for newly provisioned users."
|
||||
},
|
||||
"useradd_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to create a new user."
|
||||
},
|
||||
"userdel_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to delete a user."
|
||||
},
|
||||
"usermod_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to modify a user's groups."
|
||||
},
|
||||
"gpasswd_add_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to add a user to a group."
|
||||
},
|
||||
"gpasswd_remove_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to remove a user from a group."
|
||||
},
|
||||
"groupadd_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to create a new group."
|
||||
}
|
||||
}
|
||||
},
|
||||
"Daemons": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Daemons section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"accounts_daemon": {
|
||||
"type": "boolean",
|
||||
"description": "Disables the accounts daemon."
|
||||
},
|
||||
"clock_skew_daemon": {
|
||||
"type": "boolean",
|
||||
"description": "Disables the clock skew daemon."
|
||||
},
|
||||
"network_daemon": {
|
||||
"type": "boolean",
|
||||
"description": "Disables the network daemon."
|
||||
}
|
||||
}
|
||||
},
|
||||
"InstanceSetup": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "InstanceSetup section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"host_key_types": {
|
||||
"type": "array",
|
||||
"description": "List of host key types to generate."
|
||||
},
|
||||
"optimize_local_ssd": {
|
||||
"type": "boolean",
|
||||
"description": "Prevents optimizing for local SSD."
|
||||
},
|
||||
"network_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Skips instance setup functions that require metadata."
|
||||
},
|
||||
"set_boto_config": {
|
||||
"type": "boolean",
|
||||
"description": "Skip setting up a boto config."
|
||||
},
|
||||
"set_host_keys": {
|
||||
"type": "boolean",
|
||||
"description": "Skips generating host keys on first boot."
|
||||
},
|
||||
"set_multiqueue": {
|
||||
"type": "boolean",
|
||||
"description": "Skips multiqueue driver support."
|
||||
}
|
||||
}
|
||||
},
|
||||
"IpForwarding": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "IpForwarding section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"ethernet_proto_id": {
|
||||
"type": "string",
|
||||
"description": "Protocol ID string for daemon added routes."
|
||||
},
|
||||
"ip_aliases": {
|
||||
"type": "boolean",
|
||||
"description": "Disables setting up alias IP routes."
|
||||
},
|
||||
"target_instance_ips": {
|
||||
"type": "boolean",
|
||||
"description": "Disables internal IP address load balancing."
|
||||
}
|
||||
}
|
||||
},
|
||||
"MetadataScripts": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "MetadataScripts section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"default_shell": {
|
||||
"type": "string",
|
||||
"description": "String with the default shell to execute scripts."
|
||||
},
|
||||
"run_dir": {
|
||||
"type": "string",
|
||||
"description": "String base directory where metadata scripts are executed."
|
||||
},
|
||||
"startup": {
|
||||
"type": "boolean",
|
||||
"description": "Disables startup script execution."
|
||||
},
|
||||
"shutdown": {
|
||||
"type": "boolean",
|
||||
"description": "Disables shutdown script execution."
|
||||
}
|
||||
}
|
||||
},
|
||||
"NetworkInterfaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "NetworkInterfaces section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"setup": {
|
||||
"type": "boolean",
|
||||
"description": "Skips network interface setup."
|
||||
},
|
||||
"ip_forwarding": {
|
||||
"type": "boolean",
|
||||
"description": "Skips IP forwarding."
|
||||
},
|
||||
"dhcp_command": {
|
||||
"type": "string",
|
||||
"description": "Path for alternate dhcp executable used to enable network interfaces."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["config"],
|
||||
"description": "Configure GCP guest-agent.",
|
||||
"properties": {
|
||||
"config_scope": {
|
||||
"type": "string",
|
||||
"description": "Create distro-wide or instance-specific configuration.",
|
||||
"enum": ["distro", "instance"],
|
||||
"default": "distro"
|
||||
},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "GCP guest-agent configuration.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"Accounts": {
|
||||
"$ref": "#/definitions/Accounts"
|
||||
},
|
||||
"Daemons": {
|
||||
"$ref": "#/definitions/Daemons"
|
||||
},
|
||||
"InstanceSetup": {
|
||||
"$ref": "#/definitions/InstanceSetup"
|
||||
},
|
||||
"IpForwarding": {
|
||||
"$ref": "#/definitions/IpForwarding"
|
||||
},
|
||||
"MetadataScripts": {
|
||||
"$ref": "#/definitions/MetadataScripts"
|
||||
},
|
||||
"NetworkInterfaces": {
|
||||
"$ref": "#/definitions/NetworkInterfaces"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def option_value_to_str(value):
|
||||
"""
|
||||
|
|
|
|||
213
stages/org.osbuild.gcp.guest-agent.conf.meta.json
Normal file
213
stages/org.osbuild.gcp.guest-agent.conf.meta.json
Normal file
|
|
@ -0,0 +1,213 @@
|
|||
{
|
||||
"summary": "Create or modify the GCP guest-agent config",
|
||||
"description": [
|
||||
"Create or modify the GCP guest-agent config, depending on the",
|
||||
"scope either at:",
|
||||
" /etc/default/instance_configs.cfg.distro or",
|
||||
" /etc/default/instance_configs.cfg",
|
||||
"Configuration sections and options may contain any of these values:",
|
||||
"https://github.com/GoogleCloudPlatform/guest-agent#configuration"
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"Accounts": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Accounts section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"deprovision_remove": {
|
||||
"type": "boolean",
|
||||
"description": "Makes deprovisioning a user destructive."
|
||||
},
|
||||
"groups": {
|
||||
"type": "array",
|
||||
"description": "List of groups for newly provisioned users."
|
||||
},
|
||||
"useradd_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to create a new user."
|
||||
},
|
||||
"userdel_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to delete a user."
|
||||
},
|
||||
"usermod_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to modify a user's groups."
|
||||
},
|
||||
"gpasswd_add_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to add a user to a group."
|
||||
},
|
||||
"gpasswd_remove_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to remove a user from a group."
|
||||
},
|
||||
"groupadd_cmd": {
|
||||
"type": "string",
|
||||
"description": "Command string to create a new group."
|
||||
}
|
||||
}
|
||||
},
|
||||
"Daemons": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Daemons section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"accounts_daemon": {
|
||||
"type": "boolean",
|
||||
"description": "Disables the accounts daemon."
|
||||
},
|
||||
"clock_skew_daemon": {
|
||||
"type": "boolean",
|
||||
"description": "Disables the clock skew daemon."
|
||||
},
|
||||
"network_daemon": {
|
||||
"type": "boolean",
|
||||
"description": "Disables the network daemon."
|
||||
}
|
||||
}
|
||||
},
|
||||
"InstanceSetup": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "InstanceSetup section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"host_key_types": {
|
||||
"type": "array",
|
||||
"description": "List of host key types to generate."
|
||||
},
|
||||
"optimize_local_ssd": {
|
||||
"type": "boolean",
|
||||
"description": "Prevents optimizing for local SSD."
|
||||
},
|
||||
"network_enabled": {
|
||||
"type": "boolean",
|
||||
"description": "Skips instance setup functions that require metadata."
|
||||
},
|
||||
"set_boto_config": {
|
||||
"type": "boolean",
|
||||
"description": "Skip setting up a boto config."
|
||||
},
|
||||
"set_host_keys": {
|
||||
"type": "boolean",
|
||||
"description": "Skips generating host keys on first boot."
|
||||
},
|
||||
"set_multiqueue": {
|
||||
"type": "boolean",
|
||||
"description": "Skips multiqueue driver support."
|
||||
}
|
||||
}
|
||||
},
|
||||
"IpForwarding": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "IpForwarding section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"ethernet_proto_id": {
|
||||
"type": "string",
|
||||
"description": "Protocol ID string for daemon added routes."
|
||||
},
|
||||
"ip_aliases": {
|
||||
"type": "boolean",
|
||||
"description": "Disables setting up alias IP routes."
|
||||
},
|
||||
"target_instance_ips": {
|
||||
"type": "boolean",
|
||||
"description": "Disables internal IP address load balancing."
|
||||
}
|
||||
}
|
||||
},
|
||||
"MetadataScripts": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "MetadataScripts section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"default_shell": {
|
||||
"type": "string",
|
||||
"description": "String with the default shell to execute scripts."
|
||||
},
|
||||
"run_dir": {
|
||||
"type": "string",
|
||||
"description": "String base directory where metadata scripts are executed."
|
||||
},
|
||||
"startup": {
|
||||
"type": "boolean",
|
||||
"description": "Disables startup script execution."
|
||||
},
|
||||
"shutdown": {
|
||||
"type": "boolean",
|
||||
"description": "Disables shutdown script execution."
|
||||
}
|
||||
}
|
||||
},
|
||||
"NetworkInterfaces": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "NetworkInterfaces section.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"setup": {
|
||||
"type": "boolean",
|
||||
"description": "Skips network interface setup."
|
||||
},
|
||||
"ip_forwarding": {
|
||||
"type": "boolean",
|
||||
"description": "Skips IP forwarding."
|
||||
},
|
||||
"dhcp_command": {
|
||||
"type": "string",
|
||||
"description": "Path for alternate dhcp executable used to enable network interfaces."
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"config"
|
||||
],
|
||||
"description": "Configure GCP guest-agent.",
|
||||
"properties": {
|
||||
"config_scope": {
|
||||
"type": "string",
|
||||
"description": "Create distro-wide or instance-specific configuration.",
|
||||
"enum": [
|
||||
"distro",
|
||||
"instance"
|
||||
],
|
||||
"default": "distro"
|
||||
},
|
||||
"config": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "GCP guest-agent configuration.",
|
||||
"minProperties": 1,
|
||||
"properties": {
|
||||
"Accounts": {
|
||||
"$ref": "#/definitions/Accounts"
|
||||
},
|
||||
"Daemons": {
|
||||
"$ref": "#/definitions/Daemons"
|
||||
},
|
||||
"InstanceSetup": {
|
||||
"$ref": "#/definitions/InstanceSetup"
|
||||
},
|
||||
"IpForwarding": {
|
||||
"$ref": "#/definitions/IpForwarding"
|
||||
},
|
||||
"MetadataScripts": {
|
||||
"$ref": "#/definitions/MetadataScripts"
|
||||
},
|
||||
"NetworkInterfaces": {
|
||||
"$ref": "#/definitions/NetworkInterfaces"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure greenboot
|
||||
|
||||
Update configuration of greenboot in /etc/greenboot/greenbot.conf.
|
||||
"""
|
||||
|
||||
import fileinput
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["config"],
|
||||
"properties": {
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"description": "greenboot config options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"monitor_services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
greenboot_conf = options.get("config", {})
|
||||
|
|
|
|||
27
stages/org.osbuild.greenboot.meta.json
Normal file
27
stages/org.osbuild.greenboot.meta.json
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"summary": "Configure greenboot",
|
||||
"description": [
|
||||
"Update configuration of greenboot in /etc/greenboot/greenbot.conf."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"config"
|
||||
],
|
||||
"properties": {
|
||||
"config": {
|
||||
"additionalProperties": false,
|
||||
"description": "greenboot config options",
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"monitor_services": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +1,9 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create group accounts
|
||||
|
||||
Create group accounts, optionally assigning them static GIDs.
|
||||
|
||||
Runs `groupadd` from the buildhost to create the groups listed in `groups`.
|
||||
If no `gid` is given, `groupadd` will choose one.
|
||||
|
||||
If the specified group name or GID is already in use, this stage will fail.
|
||||
"""
|
||||
|
||||
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"groups": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Keys are group names, values are objects with group info",
|
||||
"patternProperties": {
|
||||
"^[A-Za-z0-9_][A-Za-z0-9_-]{0,31}$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"gid": {
|
||||
"type": "number",
|
||||
"description": "GID for this group"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def groupadd(root, name, gid=None):
|
||||
arguments = []
|
||||
|
|
|
|||
30
stages/org.osbuild.groups.meta.json
Normal file
30
stages/org.osbuild.groups.meta.json
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
{
|
||||
"summary": "Create group accounts",
|
||||
"description": [
|
||||
"Create group accounts, optionally assigning them static GIDs.",
|
||||
"Runs `groupadd` from the buildhost to create the groups listed in `groups`.",
|
||||
"If no `gid` is given, `groupadd` will choose one.",
|
||||
"If the specified group name or GID is already in use, this stage will fail."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"groups": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"description": "Keys are group names, values are objects with group info",
|
||||
"patternProperties": {
|
||||
"^[A-Za-z0-9_][A-Za-z0-9_-]{0,31}$": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"gid": {
|
||||
"type": "number",
|
||||
"description": "GID for this group"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,80 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure GRUB2 bootloader and set boot options
|
||||
|
||||
Configure the system to use GRUB2 as the bootloader, and set boot options.
|
||||
|
||||
Sets the GRUB2 boot/root filesystem to `rootfs`. If a separated boot
|
||||
partition is used it can be specified via `bootfs`. The file-systems
|
||||
can be identified either via uuid (`{"uuid": "<uuid>"}`) or label
|
||||
(`{"label": "<label>"}`). The kernel boot argument will be composed
|
||||
of the root file system id and additional options specified in
|
||||
`{kernel_opts}`, if any.
|
||||
|
||||
Configures GRUB2 to boot via the Boot Loader Specification
|
||||
(https://systemd.io/BOOT_LOADER_SPECIFICATION), which is the default
|
||||
behavior in Fedora 30 and later.
|
||||
|
||||
This stage will overwrite `/etc/default/grub`, `/boot/grub2/grubenv`, and
|
||||
`/boot/grub2/grub.cfg`. (Leading directories will be created if not present.)
|
||||
|
||||
If Legacy boot support is requested via `legacy` this stage will also
|
||||
overwrite `/boot/grub2/grub.cfg` and will copy the GRUB2 files from the
|
||||
buildhost into the target tree:
|
||||
* `/usr/share/grub/unicode.pf2` -> `/boot/grub2/fonts/`
|
||||
* `/usr/lib/grub/$platform/*.{mod,lst}` -> `/boot/grub2/$platform/`
|
||||
* NOTE: skips `fdt.lst`, which is an empty file
|
||||
The $platform variable (default: i386-pc) refers to target platform
|
||||
that grub2 is mean to ran on (see grub-install(1)'s `--target`)
|
||||
|
||||
NB: with legacy support enabled, this stage will fail if the buildhost
|
||||
doesn't have `/usr/lib/grub/$platform/` and `/usr/share/grub/unicode.pf2`.
|
||||
|
||||
If UEFI support is enabled via `uefi: {"vendor": "<vendor>"}` this stage will
|
||||
also write the `grub.cfg` to `boot/efi/EFI/<vendor>/grub.cfg`. EFI binaries
|
||||
and accompanying data can be installed from the built root via `uefi.install`.
|
||||
|
||||
Both UEFI and Legacy can be specified at the same time (hybrid boot).
|
||||
|
||||
If `uefi.unified` is specified or hybrid boot is enabled, the main grub config
|
||||
will be written to `boot/grub2/grub.cfg` and a redirect config will be placed
|
||||
in the EFI directory.
|
||||
|
||||
If the `saved_entry` option is present it will result in an entry in the
|
||||
`grubenv` file of the same name. The grub config file contains logic so
|
||||
that this variable will be used to select the next boot entry. This will
|
||||
also make grub2-reboot and grub2-set-default tools work. It will also
|
||||
prevent newly installed non-default kernels (like e.g. the debug kernel)
|
||||
to be selected as default. The contents of variable needs to match the
|
||||
corresponding loader entry, which currently is a combination of the
|
||||
machine id and kernel NVRA, like e.g.:
|
||||
`ffffffffffffffffffffffffffffffff-5.6.6-300.fc32.x86_64`
|
||||
If `saved_entry` is set it is advisable to set `config.default` to
|
||||
`saved` so that any re-creation of the grub configuration by the
|
||||
user will preserve that functionality.
|
||||
|
||||
Support for "greenboot" can be turned on via the `greenboot` option.
|
||||
Greenboot is the idea of automatically rolling back bad updates,
|
||||
i.e. updates that do not boot successfully. The implementation
|
||||
is split between the boot loader and a user space component.
|
||||
The latter sets two variables `boot_counter`, which indicates
|
||||
the maximum number of boot attempts and `boot_success` which
|
||||
tells the boot laoder if a previous boot was successful. The
|
||||
bootloader on the other hand will decrement the counter variable
|
||||
and reset the success indicator one.
|
||||
An implementation of the user space component for rpm-ostree is
|
||||
called `greenboot`.
|
||||
|
||||
Support for ignition (https://github.com/coreos/ignition) can be turned
|
||||
on via the `ignition` option. If enabled, a 'ignition_firstboot' variable
|
||||
will be created, which is meant to be included in the kernel command line.
|
||||
The grub.cfg will then contain the necessary code to detect and source
|
||||
the '/boot/ignition.firstboot' file and configure said 'ignition_firstboot'
|
||||
variable appropriately. See the 'org.osbuild.ignition' stage for more
|
||||
information on that file.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import string
|
||||
|
|
@ -82,164 +6,6 @@ import sys
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"oneOf": [{
|
||||
"required": ["root_fs_uuid"]
|
||||
}, {
|
||||
"required": ["rootfs"]
|
||||
}],
|
||||
"definitions": {
|
||||
"uuid": {
|
||||
"description": "Identify the file system by UUID",
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{ "pattern": "^[0-9A-Za-z]{8}(-[0-9A-Za-z]{4}){3}-[0-9A-Za-z]{12}$",
|
||||
"examples": ["9c6ae55b-cf88-45b8-84e8-64990759f39d"] },
|
||||
{ "pattern": "^[0-9A-Za-z]{4}-[0-9A-Za-z]{4}$",
|
||||
"examples": ["6699-AFB5"] }
|
||||
]
|
||||
},
|
||||
"filesystem": {
|
||||
"description": "Description of how to locate a file system",
|
||||
"type": "object",
|
||||
"oneOf": [{
|
||||
"required": ["uuid"]
|
||||
}, {
|
||||
"required": ["label"]
|
||||
}],
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "Identify the file system by label",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": { "$ref": "#/definitions/uuid" }
|
||||
}
|
||||
},
|
||||
"terminal": {
|
||||
"description": "Terminal device",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"rootfs": { "$ref": "#/definitions/filesystem" },
|
||||
"bootfs": { "$ref": "#/definitions/filesystem" },
|
||||
"root_fs_uuid": { "$ref": "#/definitions/uuid" },
|
||||
"boot_fs_uuid": { "$ref": "#/definitions/uuid" },
|
||||
"kernel_opts": {
|
||||
"description": "Additional kernel boot options",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"legacy": {
|
||||
"description": "Include legacy boot support",
|
||||
"oneOf": [
|
||||
{"type": "boolean", "default": false},
|
||||
{"type": "string"}
|
||||
]
|
||||
},
|
||||
"uefi": {
|
||||
"description": "Include UEFI boot support",
|
||||
"type": "object",
|
||||
"required": ["vendor"],
|
||||
"properties": {
|
||||
"vendor": {
|
||||
"type": "string",
|
||||
"description": "The vendor of the UEFI binaries (this is us)",
|
||||
"examples": ["fedora"],
|
||||
"pattern": "^(.+)$"
|
||||
},
|
||||
"efi_src_dir": {
|
||||
"type": "string",
|
||||
"description": "The source path to use for the EFI/ binaries when installing is set to True",
|
||||
"default": "/boot/efi/EFI"
|
||||
},
|
||||
"install": {
|
||||
"description": "Install EFI binaries and data from the build root",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"unified": {
|
||||
"description": "Main grub config in 'boot/grub2/grub.cfg'",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"saved_entry": {
|
||||
"description": "Set the variable of the same name in `grubenv`.",
|
||||
"type": "string"
|
||||
},
|
||||
"write_defaults": {
|
||||
"description": "Whether to write /etc/defaults/grub",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"write_cmdline": {
|
||||
"description": "Include the kernel command line in `grubenv`",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"ignition": {
|
||||
"description": "Include ignition support in the grub.cfg",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"greenboot": {
|
||||
"description": "Include support for fallback counting",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"config": {
|
||||
"description": "Configuration options for grub itself",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"default": {
|
||||
"description": "Default boot entry",
|
||||
"type": "string"
|
||||
},
|
||||
"disable_recovery": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"disable_submenu": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"distributor": {
|
||||
"description": "Name of the distributor",
|
||||
"type": "string"
|
||||
},
|
||||
"terminal": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_input": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_output": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"timeout_style": {
|
||||
"type": "string",
|
||||
"enum": ["hidden", "menu", "countdown"]
|
||||
},
|
||||
"serial": {
|
||||
"description": "The command to configure the serial console",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# The main grub2 configuration file template. Used for UEFI and legacy
|
||||
# boot. The parameters are currently:
|
||||
|
|
|
|||
|
|
@ -1,46 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Install the grub2 boot loader for non-UEFI systems or hybrid boot
|
||||
|
||||
This stage can be used to generate a grub2 core image and install
|
||||
it to the correct location to enable booting of non-UEFI systems,
|
||||
i.e. x86 legacy and PPC64LE (Open Firmware).
|
||||
|
||||
On x86, the core image can be installed into the MBR gap or to a
|
||||
dedicated BIOS boot partition when the partition label is GTP. On
|
||||
ppc64le with Open Firmware a dedicated 'PrEP partition' is used.
|
||||
|
||||
x86 / MBR gap:
|
||||
For historic and performance reasons the first partition
|
||||
is aligned to a specific sector number (used to be 64,
|
||||
now it is 2048), which leaves a gap between it and the MBR,
|
||||
where the core image can be embedded in
|
||||
|
||||
x86 / BIOS boot:
|
||||
A dedicated partition with a specific GUID[1] is used.
|
||||
|
||||
ppc64le / Open Firmware:
|
||||
A dedicated partition with a specified GUID[2] is used.
|
||||
|
||||
On ppc64le with Open Firmware a special partition called
|
||||
'PrEP partition' is used the store the grub2 core; the
|
||||
firmware looks for this partition and directly loads and
|
||||
executes the core form it.
|
||||
|
||||
On x86, a "boot image", aka grub stage 1, is installed into the
|
||||
master boot record (MBR) of the partition (even in the case the
|
||||
partition layout is GPT). It main purpose is to load the second
|
||||
stage (core image). Therefore the location of the core image is
|
||||
patched into the boot image.
|
||||
|
||||
On ppc64le, the firmware itself directly loads the complete core
|
||||
image and transfers control to it.
|
||||
|
||||
[1] 21686148-6449-6E6F-744E-656564454649
|
||||
[2] 9E1A2D38-C612-4316-AA26-8B49521E5A8B
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import struct
|
||||
|
|
@ -50,92 +8,6 @@ from typing import BinaryIO, Dict
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = r"""
|
||||
"definitions": {
|
||||
"core-mkimage": {
|
||||
"type": "object",
|
||||
"description": "Generate the core image via grub-mkimage",
|
||||
"additionalProperties": false,
|
||||
"required": ["type", "partlabel", "filesystem"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["mkimage"]
|
||||
},
|
||||
"partlabel": {
|
||||
"type": "string",
|
||||
"enum": ["gpt", "dos"]
|
||||
},
|
||||
"filesystem": {
|
||||
"type": "string",
|
||||
"enum": ["ext4", "xfs", "btrfs"]
|
||||
},
|
||||
"binary": {
|
||||
"description": "grub-mkimage binary name",
|
||||
"type": "string",
|
||||
"default": "grub2-mkimage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"prefix-partition": {
|
||||
"type": "object",
|
||||
"description": "Grub2 config on a specific partition, e.g. (,gpt3)/boot",
|
||||
"additionalProperties": false,
|
||||
"required": ["type", "partlabel", "number", "path"],
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["partition"]
|
||||
},
|
||||
"partlabel": {
|
||||
"type": "string",
|
||||
"enum": ["gpt", "dos"]
|
||||
},
|
||||
"number": {
|
||||
"description": "The partition number, starting at zero",
|
||||
"type": "number"
|
||||
},
|
||||
"path": {
|
||||
"description": "location of grub config inside the partition",
|
||||
"type": "string",
|
||||
"pattern": "\/.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["filename", "platform", "location", "core", "prefix"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "filename of the disk image"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string",
|
||||
"description": "Platform of the target system"
|
||||
},
|
||||
"location": {
|
||||
"type": "integer",
|
||||
"description": "Location of the stage 2 (in sectors)"
|
||||
},
|
||||
"core": {
|
||||
"description": "How to obtain the GRUB core image",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/core-mkimage"}
|
||||
]
|
||||
},
|
||||
"prefix": {
|
||||
"description": "location of grub config",
|
||||
"oneOf": [
|
||||
{"$ref": "#/definitions/prefix-partition"}
|
||||
]
|
||||
},
|
||||
"sector-size": {
|
||||
"type": "number",
|
||||
"description": "Sector size (in bytes)",
|
||||
"default": 512
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def grub2_partition_id(label):
|
||||
"""grub2 partition identifier for the partition table"""
|
||||
|
|
|
|||
151
stages/org.osbuild.grub2.inst.meta.json
Normal file
151
stages/org.osbuild.grub2.inst.meta.json
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
{
|
||||
"summary": "Install the grub2 boot loader for non-UEFI systems or hybrid boot",
|
||||
"description": [
|
||||
"This stage can be used to generate a grub2 core image and install",
|
||||
"it to the correct location to enable booting of non-UEFI systems,",
|
||||
"i.e. x86 legacy and PPC64LE (Open Firmware).",
|
||||
"On x86, the core image can be installed into the MBR gap or to a",
|
||||
"dedicated BIOS boot partition when the partition label is GTP. On",
|
||||
"ppc64le with Open Firmware a dedicated 'PrEP partition' is used.",
|
||||
"x86 / MBR gap:",
|
||||
" For historic and performance reasons the first partition",
|
||||
" is aligned to a specific sector number (used to be 64,",
|
||||
" now it is 2048), which leaves a gap between it and the MBR,",
|
||||
" where the core image can be embedded in",
|
||||
"x86 / BIOS boot:",
|
||||
" A dedicated partition with a specific GUID[1] is used.",
|
||||
"ppc64le / Open Firmware:",
|
||||
" A dedicated partition with a specified GUID[2] is used.",
|
||||
" On ppc64le with Open Firmware a special partition called",
|
||||
" 'PrEP partition' is used the store the grub2 core; the",
|
||||
" firmware looks for this partition and directly loads and",
|
||||
" executes the core form it.",
|
||||
"On x86, a \"boot image\", aka grub stage 1, is installed into the",
|
||||
"master boot record (MBR) of the partition (even in the case the",
|
||||
"partition layout is GPT). It main purpose is to load the second",
|
||||
"stage (core image). Therefore the location of the core image is",
|
||||
"patched into the boot image.",
|
||||
"On ppc64le, the firmware itself directly loads the complete core",
|
||||
"image and transfers control to it.",
|
||||
"[1] 21686148-6449-6E6F-744E-656564454649",
|
||||
"[2] 9E1A2D38-C612-4316-AA26-8B49521E5A8B"
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"core-mkimage": {
|
||||
"type": "object",
|
||||
"description": "Generate the core image via grub-mkimage",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"type",
|
||||
"partlabel",
|
||||
"filesystem"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [
|
||||
"mkimage"
|
||||
]
|
||||
},
|
||||
"partlabel": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"gpt",
|
||||
"dos"
|
||||
]
|
||||
},
|
||||
"filesystem": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"ext4",
|
||||
"xfs",
|
||||
"btrfs"
|
||||
]
|
||||
},
|
||||
"binary": {
|
||||
"description": "grub-mkimage binary name",
|
||||
"type": "string",
|
||||
"default": "grub2-mkimage"
|
||||
}
|
||||
}
|
||||
},
|
||||
"prefix-partition": {
|
||||
"type": "object",
|
||||
"description": "Grub2 config on a specific partition, e.g. (,gpt3)/boot",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"type",
|
||||
"partlabel",
|
||||
"number",
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": [
|
||||
"partition"
|
||||
]
|
||||
},
|
||||
"partlabel": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"gpt",
|
||||
"dos"
|
||||
]
|
||||
},
|
||||
"number": {
|
||||
"description": "The partition number, starting at zero",
|
||||
"type": "number"
|
||||
},
|
||||
"path": {
|
||||
"description": "location of grub config inside the partition",
|
||||
"type": "string",
|
||||
"pattern": "/.*"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"filename",
|
||||
"platform",
|
||||
"location",
|
||||
"core",
|
||||
"prefix"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "filename of the disk image"
|
||||
},
|
||||
"platform": {
|
||||
"type": "string",
|
||||
"description": "Platform of the target system"
|
||||
},
|
||||
"location": {
|
||||
"type": "integer",
|
||||
"description": "Location of the stage 2 (in sectors)"
|
||||
},
|
||||
"core": {
|
||||
"description": "How to obtain the GRUB core image",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/core-mkimage"
|
||||
}
|
||||
]
|
||||
},
|
||||
"prefix": {
|
||||
"description": "location of grub config",
|
||||
"oneOf": [
|
||||
{
|
||||
"$ref": "#/definitions/prefix-partition"
|
||||
}
|
||||
]
|
||||
},
|
||||
"sector-size": {
|
||||
"type": "number",
|
||||
"description": "Sector size (in bytes)",
|
||||
"default": 512
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create a boot filesystem tree, can be consumed to create
|
||||
an efiboot.img.
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import string
|
||||
|
|
@ -11,65 +6,6 @@ import sys
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["product", "kernel", "isolabel"],
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "version"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"version": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"type": "object",
|
||||
"required": ["dir"],
|
||||
"properties": {
|
||||
"dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"opts": {
|
||||
"description": "Array of group names for this user",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isolabel": {
|
||||
"type": "string"
|
||||
},
|
||||
"architectures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"config": {
|
||||
"description": "Configuration options for grub itself",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# The main grub2 configuration file template. Used for UEFI.
|
||||
GRUB2_EFI_CFG_TEMPLATE = """
|
||||
|
|
|
|||
75
stages/org.osbuild.grub2.iso.meta.json
Normal file
75
stages/org.osbuild.grub2.iso.meta.json
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
{
|
||||
"summary": "Create a boot filesystem tree, can be consumed to create\nan efiboot.img.",
|
||||
"description": [],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"product",
|
||||
"kernel",
|
||||
"isolabel"
|
||||
],
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dir"
|
||||
],
|
||||
"properties": {
|
||||
"dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"opts": {
|
||||
"description": "Array of group names for this user",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"isolabel": {
|
||||
"type": "string"
|
||||
},
|
||||
"architectures": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
},
|
||||
"vendor": {
|
||||
"type": "string"
|
||||
},
|
||||
"config": {
|
||||
"description": "Configuration options for grub itself",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 60
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Configure GRUB2 bootloader and set boot options (legacy, i.e. non-BLS)
|
||||
|
||||
This stage creates traditional menu entries for systems that are not
|
||||
capable of using the Booloader Specific (BLS).
|
||||
|
||||
Sets the GRUB2 boot/root filesystem to `rootfs`. If a separated boot
|
||||
partition is used it can be specified via `bootfs`. The file-systems
|
||||
can be identified either via
|
||||
- uuid (`{"uuid": "<uuid>"}`)
|
||||
- label (`{"label": "<label>"}`)
|
||||
- device (`{"device": "<device>"}`, only for the root file system)
|
||||
|
||||
The kernel boot argument will be composed of the root file system id
|
||||
and additional options specified in `config.cmdline`, if any.
|
||||
|
||||
This stage will overwrite `/etc/default/grub`, `/boot/grub2/grubenv`;
|
||||
leading directories will be created if not present.
|
||||
|
||||
The stage supports configuring grub for BIOS boot and UEFI systems:
|
||||
|
||||
If BIOS boot support is requested via `bios` this stage will also
|
||||
overwrite `/boot/grub2/grub.cfg` and will copy the GRUB2 files from the
|
||||
buildhost into the target tree:
|
||||
* `/usr/share/grub/unicode.pf2` -> `/boot/grub2/fonts/`
|
||||
* `/usr/lib/grub/$platform/*.{mod,lst}` -> `/boot/grub2/$platform/`
|
||||
* NOTE: skips `fdt.lst`, which is an empty file
|
||||
|
||||
NB: with bios support enabled, this stage will fail if the buildhost
|
||||
doesn't have `/usr/lib/grub/$platform/` and `/usr/share/grub/unicode.pf2`.
|
||||
|
||||
If UEFI support is enabled via `uefi: {"vendor": "<vendor>"}` this stage will
|
||||
also write the `grub.cfg` to `boot/efi/EFI/<vendor>/grub.cfg`. EFI binaries
|
||||
and accompanying data can be installed from the built root via `uefi.install`.
|
||||
|
||||
Both UEFI and Legacy can be specified at the same time (hybrid boot).
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import string
|
||||
|
|
@ -45,181 +6,6 @@ import sys
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
|
||||
"definitions": {
|
||||
"filesystem": {
|
||||
"description": "Description of how to locate a file system",
|
||||
"type": "object",
|
||||
"oneOf": [{
|
||||
"required": ["uuid"]
|
||||
}, {
|
||||
"required": ["label"]
|
||||
}, {
|
||||
"required": ["device"]
|
||||
}],
|
||||
"properties": {
|
||||
"device": {
|
||||
"description": "Identify the file system by device node",
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"description": "Identify the file system by label",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "Identify the file system by UUID",
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{ "pattern": "^[0-9A-Za-z]{8}(-[0-9A-Za-z]{4}){3}-[0-9A-Za-z]{12}$",
|
||||
"examples": ["9c6ae55b-cf88-45b8-84e8-64990759f39d"] },
|
||||
{ "pattern": "^[0-9A-Za-z]{4}-[0-9A-Za-z]{4}$",
|
||||
"examples": ["6699-AFB5"] }
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"terminal": {
|
||||
"description": "Terminal device",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": ["rootfs", "entries"],
|
||||
"anyOf": [{
|
||||
"required": ["bios"]
|
||||
}, {
|
||||
"required": ["uefi"]
|
||||
}],
|
||||
"properties": {
|
||||
"rootfs": { "$ref": "#/definitions/filesystem" },
|
||||
"bootfs": { "$ref": "#/definitions/filesystem" },
|
||||
"bios": {
|
||||
"description": "Include bios boot support",
|
||||
"type": "object",
|
||||
"required": ["platform"],
|
||||
"properties": {
|
||||
"platform": {
|
||||
"type": "string",
|
||||
"enum": ["i386-pc", "powerpc-ieee1275"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"uefi": {
|
||||
"description": "Include UEFI boot support",
|
||||
"type": "object",
|
||||
"required": ["vendor"],
|
||||
"properties": {
|
||||
"vendor": {
|
||||
"type": "string",
|
||||
"description": "The vendor of the UEFI binaries (this is us)",
|
||||
"examples": ["fedora"],
|
||||
"pattern": "^(.+)$"
|
||||
},
|
||||
"install": {
|
||||
"description": "Install EFI binaries and data from the build root",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"write_defaults": {
|
||||
"description": "Whether to write /etc/defaults/grub",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"entries": {
|
||||
"description": "List of entries to add to the boot menu",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["id", "product", "kernel"],
|
||||
"properties": {
|
||||
"default": {
|
||||
"type": "boolean",
|
||||
"description": "Make this entry the default entry"
|
||||
},
|
||||
"id": {
|
||||
"description": "UUID for the entry (grub uses the root fs uuid)",
|
||||
"type": "string"
|
||||
},
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "version"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"nick": {"type": "string"},
|
||||
"version": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"description": "The kernel (EVRA)",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"description": "Configuration options for grub itself",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"cmdline": {
|
||||
"description": "Additional kernel command line options",
|
||||
"type": "string"
|
||||
},
|
||||
"default": {
|
||||
"description": "Default boot entry",
|
||||
"type": "string",
|
||||
"default": "saved"
|
||||
},
|
||||
"disable_recovery": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"disable_submenu": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"distributor": {
|
||||
"description": "Name of the distributor",
|
||||
"type": "string"
|
||||
},
|
||||
"terminal": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_input": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_output": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"timeout_style": {
|
||||
"type": "string",
|
||||
"enum": ["hidden", "menu", "countdown"],
|
||||
"default": "countdown"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The command to configure the serial console",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# The main grub2 configuration file template. Used for UEFI and legacy
|
||||
GRUB_CFG_TEMPLATE = """
|
||||
|
|
|
|||
261
stages/org.osbuild.grub2.legacy.meta.json
Normal file
261
stages/org.osbuild.grub2.legacy.meta.json
Normal file
|
|
@ -0,0 +1,261 @@
|
|||
{
|
||||
"summary": "Configure GRUB2 bootloader and set boot options (legacy, i.e. non-BLS)",
|
||||
"description": [
|
||||
"This stage creates traditional menu entries for systems that are not",
|
||||
"capable of using the Booloader Specific (BLS).",
|
||||
"Sets the GRUB2 boot/root filesystem to `rootfs`. If a separated boot",
|
||||
"partition is used it can be specified via `bootfs`. The file-systems",
|
||||
"can be identified either via",
|
||||
" - uuid (`{\"uuid\": \"<uuid>\"}`)",
|
||||
" - label (`{\"label\": \"<label>\"}`)",
|
||||
" - device (`{\"device\": \"<device>\"}`, only for the root file system)",
|
||||
"The kernel boot argument will be composed of the root file system id",
|
||||
"and additional options specified in `config.cmdline`, if any.",
|
||||
"This stage will overwrite `/etc/default/grub`, `/boot/grub2/grubenv`;",
|
||||
"leading directories will be created if not present.",
|
||||
"The stage supports configuring grub for BIOS boot and UEFI systems:",
|
||||
"If BIOS boot support is requested via `bios` this stage will also",
|
||||
"overwrite `/boot/grub2/grub.cfg` and will copy the GRUB2 files from the",
|
||||
"buildhost into the target tree:",
|
||||
"* `/usr/share/grub/unicode.pf2` -> `/boot/grub2/fonts/`",
|
||||
"* `/usr/lib/grub/$platform/*.{mod,lst}` -> `/boot/grub2/$platform/`",
|
||||
" * NOTE: skips `fdt.lst`, which is an empty file",
|
||||
"NB: with bios support enabled, this stage will fail if the buildhost",
|
||||
"doesn't have `/usr/lib/grub/$platform/` and `/usr/share/grub/unicode.pf2`.",
|
||||
"If UEFI support is enabled via `uefi: {\"vendor\": \"<vendor>\"}` this stage will",
|
||||
"also write the `grub.cfg` to `boot/efi/EFI/<vendor>/grub.cfg`. EFI binaries",
|
||||
"and accompanying data can be installed from the built root via `uefi.install`.",
|
||||
"Both UEFI and Legacy can be specified at the same time (hybrid boot)."
|
||||
],
|
||||
"schema": {
|
||||
"definitions": {
|
||||
"filesystem": {
|
||||
"description": "Description of how to locate a file system",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"uuid"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"label"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"device"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"device": {
|
||||
"description": "Identify the file system by device node",
|
||||
"type": "string"
|
||||
},
|
||||
"label": {
|
||||
"description": "Identify the file system by label",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"description": "Identify the file system by UUID",
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"pattern": "^[0-9A-Za-z]{8}(-[0-9A-Za-z]{4}){3}-[0-9A-Za-z]{12}$",
|
||||
"examples": [
|
||||
"9c6ae55b-cf88-45b8-84e8-64990759f39d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"pattern": "^[0-9A-Za-z]{4}-[0-9A-Za-z]{4}$",
|
||||
"examples": [
|
||||
"6699-AFB5"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"terminal": {
|
||||
"description": "Terminal device",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"rootfs",
|
||||
"entries"
|
||||
],
|
||||
"anyOf": [
|
||||
{
|
||||
"required": [
|
||||
"bios"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"uefi"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"rootfs": {
|
||||
"$ref": "#/definitions/filesystem"
|
||||
},
|
||||
"bootfs": {
|
||||
"$ref": "#/definitions/filesystem"
|
||||
},
|
||||
"bios": {
|
||||
"description": "Include bios boot support",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"platform"
|
||||
],
|
||||
"properties": {
|
||||
"platform": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"i386-pc",
|
||||
"powerpc-ieee1275"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
"uefi": {
|
||||
"description": "Include UEFI boot support",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"vendor": {
|
||||
"type": "string",
|
||||
"description": "The vendor of the UEFI binaries (this is us)",
|
||||
"examples": [
|
||||
"fedora"
|
||||
],
|
||||
"pattern": "^(.+)$"
|
||||
},
|
||||
"install": {
|
||||
"description": "Install EFI binaries and data from the build root",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"write_defaults": {
|
||||
"description": "Whether to write /etc/defaults/grub",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"entries": {
|
||||
"description": "List of entries to add to the boot menu",
|
||||
"type": "array",
|
||||
"minItems": 1,
|
||||
"items": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"id",
|
||||
"product",
|
||||
"kernel"
|
||||
],
|
||||
"properties": {
|
||||
"default": {
|
||||
"type": "boolean",
|
||||
"description": "Make this entry the default entry"
|
||||
},
|
||||
"id": {
|
||||
"description": "UUID for the entry (grub uses the root fs uuid)",
|
||||
"type": "string"
|
||||
},
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"nick": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"description": "The kernel (EVRA)",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"config": {
|
||||
"description": "Configuration options for grub itself",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"cmdline": {
|
||||
"description": "Additional kernel command line options",
|
||||
"type": "string"
|
||||
},
|
||||
"default": {
|
||||
"description": "Default boot entry",
|
||||
"type": "string",
|
||||
"default": "saved"
|
||||
},
|
||||
"disable_recovery": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"disable_submenu": {
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"distributor": {
|
||||
"description": "Name of the distributor",
|
||||
"type": "string"
|
||||
},
|
||||
"terminal": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_input": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_output": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"timeout_style": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hidden",
|
||||
"menu",
|
||||
"countdown"
|
||||
],
|
||||
"default": "countdown"
|
||||
},
|
||||
"serial": {
|
||||
"description": "The command to configure the serial console",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
266
stages/org.osbuild.grub2.meta.json
Normal file
266
stages/org.osbuild.grub2.meta.json
Normal file
|
|
@ -0,0 +1,266 @@
|
|||
{
|
||||
"summary": "Configure GRUB2 bootloader and set boot options",
|
||||
"description": [
|
||||
"Configure the system to use GRUB2 as the bootloader, and set boot options.",
|
||||
"Sets the GRUB2 boot/root filesystem to `rootfs`. If a separated boot",
|
||||
"partition is used it can be specified via `bootfs`. The file-systems",
|
||||
"can be identified either via uuid (`{\"uuid\": \"<uuid>\"}`) or label",
|
||||
"(`{\"label\": \"<label>\"}`). The kernel boot argument will be composed",
|
||||
"of the root file system id and additional options specified in",
|
||||
"`{kernel_opts}`, if any.",
|
||||
"Configures GRUB2 to boot via the Boot Loader Specification",
|
||||
"(https://systemd.io/BOOT_LOADER_SPECIFICATION), which is the default",
|
||||
"behavior in Fedora 30 and later.",
|
||||
"This stage will overwrite `/etc/default/grub`, `/boot/grub2/grubenv`, and",
|
||||
"`/boot/grub2/grub.cfg`. (Leading directories will be created if not present.)",
|
||||
"If Legacy boot support is requested via `legacy` this stage will also",
|
||||
"overwrite `/boot/grub2/grub.cfg` and will copy the GRUB2 files from the",
|
||||
"buildhost into the target tree:",
|
||||
"* `/usr/share/grub/unicode.pf2` -> `/boot/grub2/fonts/`",
|
||||
"* `/usr/lib/grub/$platform/*.{mod,lst}` -> `/boot/grub2/$platform/`",
|
||||
" * NOTE: skips `fdt.lst`, which is an empty file",
|
||||
"The $platform variable (default: i386-pc) refers to target platform",
|
||||
"that grub2 is mean to ran on (see grub-install(1)'s `--target`)",
|
||||
"NB: with legacy support enabled, this stage will fail if the buildhost",
|
||||
"doesn't have `/usr/lib/grub/$platform/` and `/usr/share/grub/unicode.pf2`.",
|
||||
"If UEFI support is enabled via `uefi: {\"vendor\": \"<vendor>\"}` this stage will",
|
||||
"also write the `grub.cfg` to `boot/efi/EFI/<vendor>/grub.cfg`. EFI binaries",
|
||||
"and accompanying data can be installed from the built root via `uefi.install`.",
|
||||
"Both UEFI and Legacy can be specified at the same time (hybrid boot).",
|
||||
"If `uefi.unified` is specified or hybrid boot is enabled, the main grub config",
|
||||
"will be written to `boot/grub2/grub.cfg` and a redirect config will be placed",
|
||||
"in the EFI directory.",
|
||||
"If the `saved_entry` option is present it will result in an entry in the",
|
||||
"`grubenv` file of the same name. The grub config file contains logic so",
|
||||
"that this variable will be used to select the next boot entry. This will",
|
||||
"also make grub2-reboot and grub2-set-default tools work. It will also",
|
||||
"prevent newly installed non-default kernels (like e.g. the debug kernel)",
|
||||
"to be selected as default. The contents of variable needs to match the",
|
||||
"corresponding loader entry, which currently is a combination of the",
|
||||
"machine id and kernel NVRA, like e.g.:",
|
||||
" `ffffffffffffffffffffffffffffffff-5.6.6-300.fc32.x86_64`",
|
||||
"If `saved_entry` is set it is advisable to set `config.default` to",
|
||||
"`saved` so that any re-creation of the grub configuration by the",
|
||||
"user will preserve that functionality.",
|
||||
"Support for \"greenboot\" can be turned on via the `greenboot` option.",
|
||||
"Greenboot is the idea of automatically rolling back bad updates,",
|
||||
"i.e. updates that do not boot successfully. The implementation",
|
||||
"is split between the boot loader and a user space component.",
|
||||
"The latter sets two variables `boot_counter`, which indicates",
|
||||
"the maximum number of boot attempts and `boot_success` which",
|
||||
"tells the boot laoder if a previous boot was successful. The",
|
||||
"bootloader on the other hand will decrement the counter variable",
|
||||
"and reset the success indicator one.",
|
||||
"An implementation of the user space component for rpm-ostree is",
|
||||
"called `greenboot`.",
|
||||
"Support for ignition (https://github.com/coreos/ignition) can be turned",
|
||||
"on via the `ignition` option. If enabled, a 'ignition_firstboot' variable",
|
||||
"will be created, which is meant to be included in the kernel command line.",
|
||||
"The grub.cfg will then contain the necessary code to detect and source",
|
||||
"the '/boot/ignition.firstboot' file and configure said 'ignition_firstboot'",
|
||||
"variable appropriately. See the 'org.osbuild.ignition' stage for more",
|
||||
"information on that file."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"root_fs_uuid"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"rootfs"
|
||||
]
|
||||
}
|
||||
],
|
||||
"definitions": {
|
||||
"uuid": {
|
||||
"description": "Identify the file system by UUID",
|
||||
"type": "string",
|
||||
"oneOf": [
|
||||
{
|
||||
"pattern": "^[0-9A-Za-z]{8}(-[0-9A-Za-z]{4}){3}-[0-9A-Za-z]{12}$",
|
||||
"examples": [
|
||||
"9c6ae55b-cf88-45b8-84e8-64990759f39d"
|
||||
]
|
||||
},
|
||||
{
|
||||
"pattern": "^[0-9A-Za-z]{4}-[0-9A-Za-z]{4}$",
|
||||
"examples": [
|
||||
"6699-AFB5"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"filesystem": {
|
||||
"description": "Description of how to locate a file system",
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
{
|
||||
"required": [
|
||||
"uuid"
|
||||
]
|
||||
},
|
||||
{
|
||||
"required": [
|
||||
"label"
|
||||
]
|
||||
}
|
||||
],
|
||||
"properties": {
|
||||
"label": {
|
||||
"description": "Identify the file system by label",
|
||||
"type": "string"
|
||||
},
|
||||
"uuid": {
|
||||
"$ref": "#/definitions/uuid"
|
||||
}
|
||||
}
|
||||
},
|
||||
"terminal": {
|
||||
"description": "Terminal device",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"properties": {
|
||||
"rootfs": {
|
||||
"$ref": "#/definitions/filesystem"
|
||||
},
|
||||
"bootfs": {
|
||||
"$ref": "#/definitions/filesystem"
|
||||
},
|
||||
"root_fs_uuid": {
|
||||
"$ref": "#/definitions/uuid"
|
||||
},
|
||||
"boot_fs_uuid": {
|
||||
"$ref": "#/definitions/uuid"
|
||||
},
|
||||
"kernel_opts": {
|
||||
"description": "Additional kernel boot options",
|
||||
"type": "string",
|
||||
"default": ""
|
||||
},
|
||||
"legacy": {
|
||||
"description": "Include legacy boot support",
|
||||
"oneOf": [
|
||||
{
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
{
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"uefi": {
|
||||
"description": "Include UEFI boot support",
|
||||
"type": "object",
|
||||
"required": [
|
||||
"vendor"
|
||||
],
|
||||
"properties": {
|
||||
"vendor": {
|
||||
"type": "string",
|
||||
"description": "The vendor of the UEFI binaries (this is us)",
|
||||
"examples": [
|
||||
"fedora"
|
||||
],
|
||||
"pattern": "^(.+)$"
|
||||
},
|
||||
"efi_src_dir": {
|
||||
"type": "string",
|
||||
"description": "The source path to use for the EFI/ binaries when installing is set to True",
|
||||
"default": "/boot/efi/EFI"
|
||||
},
|
||||
"install": {
|
||||
"description": "Install EFI binaries and data from the build root",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"unified": {
|
||||
"description": "Main grub config in 'boot/grub2/grub.cfg'",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"saved_entry": {
|
||||
"description": "Set the variable of the same name in `grubenv`.",
|
||||
"type": "string"
|
||||
},
|
||||
"write_defaults": {
|
||||
"description": "Whether to write /etc/defaults/grub",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"write_cmdline": {
|
||||
"description": "Include the kernel command line in `grubenv`",
|
||||
"type": "boolean",
|
||||
"default": true
|
||||
},
|
||||
"ignition": {
|
||||
"description": "Include ignition support in the grub.cfg",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"greenboot": {
|
||||
"description": "Include support for fallback counting",
|
||||
"type": "boolean",
|
||||
"default": false
|
||||
},
|
||||
"config": {
|
||||
"description": "Configuration options for grub itself",
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"default": {
|
||||
"description": "Default boot entry",
|
||||
"type": "string"
|
||||
},
|
||||
"disable_recovery": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"disable_submenu": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"distributor": {
|
||||
"description": "Name of the distributor",
|
||||
"type": "string"
|
||||
},
|
||||
"terminal": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_input": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"terminal_output": {
|
||||
"$ref": "#/definitions/terminal"
|
||||
},
|
||||
"timeout": {
|
||||
"description": "Timeout in seconds",
|
||||
"type": "integer",
|
||||
"minimum": 0,
|
||||
"default": 0
|
||||
},
|
||||
"timeout_style": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"hidden",
|
||||
"menu",
|
||||
"countdown"
|
||||
]
|
||||
},
|
||||
"serial": {
|
||||
"description": "The command to configure the serial console",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Extract a gzipped file
|
||||
|
||||
Buildhost commands used: `gunzip`.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["file"],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["path"],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "Unzip here.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def parse_input(inputs):
|
||||
image = inputs["file"]
|
||||
|
|
|
|||
33
stages/org.osbuild.gunzip.meta.json
Normal file
33
stages/org.osbuild.gunzip.meta.json
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"summary": "Extract a gzipped file",
|
||||
"description": [
|
||||
"Buildhost commands used: `gunzip`."
|
||||
],
|
||||
"schema_2": {
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"file"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"path"
|
||||
],
|
||||
"properties": {
|
||||
"path": {
|
||||
"description": "Unzip here.",
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,47 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Compress a file using gzip
|
||||
|
||||
Buildhost commands used: `gzip`.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = r"""
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["file"],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename to use for the compressed file",
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"description": "Compression level",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 9,
|
||||
"default": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def parse_input(inputs):
|
||||
image = inputs["file"]
|
||||
|
|
|
|||
40
stages/org.osbuild.gzip.meta.json
Normal file
40
stages/org.osbuild.gzip.meta.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"summary": "Compress a file using gzip",
|
||||
"description": [
|
||||
"Buildhost commands used: `gzip`."
|
||||
],
|
||||
"schema_2": {
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"file"
|
||||
],
|
||||
"properties": {
|
||||
"file": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"filename"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"description": "Filename to use for the compressed file",
|
||||
"type": "string"
|
||||
},
|
||||
"level": {
|
||||
"description": "Compression level",
|
||||
"type": "integer",
|
||||
"minimum": 1,
|
||||
"maximum": 9,
|
||||
"default": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Set system hostname
|
||||
|
||||
Sets system hostname.
|
||||
|
||||
Deletes /etc/hostname if present, then runs `systemd-firstboot` from the
|
||||
buildhost with `--hostname={hostname}`, which checks the validity of the
|
||||
hostname and writes it to /etc/hostname.
|
||||
"""
|
||||
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["hostname"],
|
||||
"properties": {
|
||||
"hostname": {
|
||||
"type": "string",
|
||||
"description": "hostname for the target system"
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
hostname = options["hostname"]
|
||||
|
|
|
|||
21
stages/org.osbuild.hostname.meta.json
Normal file
21
stages/org.osbuild.hostname.meta.json
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
{
|
||||
"summary": "Set system hostname",
|
||||
"description": [
|
||||
"Sets system hostname.",
|
||||
"Deletes /etc/hostname if present, then runs `systemd-firstboot` from the",
|
||||
"buildhost with `--hostname={hostname}`, which checks the validity of the",
|
||||
"hostname and writes it to /etc/hostname."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"hostname"
|
||||
],
|
||||
"properties": {
|
||||
"hostname": {
|
||||
"type": "string",
|
||||
"description": "hostname for the target system"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,39 +1,8 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Setup ignition so it will be triggered on first boot.
|
||||
|
||||
Create the file '/boot/ignition.firstboot' that will be used by grub,
|
||||
if the necessary ignition support is enabled, to create a variable to
|
||||
be used in the kernel command line ('ignition_firstboot'). Via this
|
||||
variable, if included in the actual kernel command line, the run of
|
||||
ignition during early boot can be controlled: if grub detects the
|
||||
aforementioned file to be present it will set 'ignition_firstboot'
|
||||
to "ignition.firstboot" which is the trigger for ignition to run.
|
||||
The "ignition-firstboot-complete.service" will remove said file and
|
||||
thus preventing ignition to be run on the next boot.
|
||||
|
||||
The `network` option can be used to overwrite the default network
|
||||
configuration, in case that ignition is run.
|
||||
"""
|
||||
|
||||
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"network": {
|
||||
"type": "array",
|
||||
"description": "Overwrite default network connection",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
network = options.get("network", [])
|
||||
|
|
|
|||
28
stages/org.osbuild.ignition.meta.json
Normal file
28
stages/org.osbuild.ignition.meta.json
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"summary": "Setup ignition so it will be triggered on first boot.",
|
||||
"description": [
|
||||
"Create the file '/boot/ignition.firstboot' that will be used by grub,",
|
||||
"if the necessary ignition support is enabled, to create a variable to",
|
||||
"be used in the kernel command line ('ignition_firstboot'). Via this",
|
||||
"variable, if included in the actual kernel command line, the run of",
|
||||
"ignition during early boot can be controlled: if grub detects the",
|
||||
"aforementioned file to be present it will set 'ignition_firstboot'",
|
||||
"to \"ignition.firstboot\" which is the trigger for ignition to run.",
|
||||
"The \"ignition-firstboot-complete.service\" will remove said file and",
|
||||
"thus preventing ignition to be run on the next boot.",
|
||||
"The `network` option can be used to overwrite the default network",
|
||||
"configuration, in case that ignition is run."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"properties": {
|
||||
"network": {
|
||||
"type": "array",
|
||||
"description": "Overwrite default network connection",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,28 +1,10 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Implant an MD5 checksum in an ISO9660 image
|
||||
|
||||
This stage is using implantisomd5(1) to implant MD5 checksums into an iso
|
||||
image. This is needed for the check media feature used in the installer.
|
||||
"""
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA = """
|
||||
"additionalProperties": false,
|
||||
"required": ["filename"],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Path to where the iso to implant md5s is located."
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
def main(tree, options):
|
||||
filename = options["filename"].lstrip("/")
|
||||
|
|
|
|||
19
stages/org.osbuild.implantisomd5.meta.json
Normal file
19
stages/org.osbuild.implantisomd5.meta.json
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"summary": "Implant an MD5 checksum in an ISO9660 image",
|
||||
"description": [
|
||||
"This stage is using implantisomd5(1) to implant MD5 checksums into an iso",
|
||||
"image. This is needed for the check media feature used in the installer."
|
||||
],
|
||||
"schema": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"filename"
|
||||
],
|
||||
"properties": {
|
||||
"filename": {
|
||||
"type": "string",
|
||||
"description": "Path to where the iso to implant md5s is located."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,4 @@
|
|||
#!/usr/bin/python3
|
||||
"""
|
||||
Create an isolinux bootloader
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
import string
|
||||
|
|
@ -10,51 +6,6 @@ import sys
|
|||
|
||||
import osbuild.api
|
||||
|
||||
SCHEMA_2 = """
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": ["product", "kernel"],
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["name", "version"],
|
||||
"properties": {
|
||||
"name": {"type": "string"},
|
||||
"version": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"type": "object",
|
||||
"required": ["dir"],
|
||||
"properties": {
|
||||
"dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"opts": {
|
||||
"description": "Array of group names for this user",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": ["data"],
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
"""
|
||||
|
||||
|
||||
# The isolinux configuration template
|
||||
ISOLINUX_CFG_TEMPLATE = """
|
||||
|
|
|
|||
62
stages/org.osbuild.isolinux.meta.json
Normal file
62
stages/org.osbuild.isolinux.meta.json
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
{
|
||||
"summary": "Create an isolinux bootloader",
|
||||
"description": [],
|
||||
"schema_2": {
|
||||
"options": {
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"product",
|
||||
"kernel"
|
||||
],
|
||||
"properties": {
|
||||
"product": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"name",
|
||||
"version"
|
||||
],
|
||||
"properties": {
|
||||
"name": {
|
||||
"type": "string"
|
||||
},
|
||||
"version": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
},
|
||||
"kernel": {
|
||||
"type": "object",
|
||||
"required": [
|
||||
"dir"
|
||||
],
|
||||
"properties": {
|
||||
"dir": {
|
||||
"type": "string"
|
||||
},
|
||||
"opts": {
|
||||
"description": "Array of group names for this user",
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"inputs": {
|
||||
"type": "object",
|
||||
"additionalProperties": false,
|
||||
"required": [
|
||||
"data"
|
||||
],
|
||||
"properties": {
|
||||
"data": {
|
||||
"type": "object",
|
||||
"additionalProperties": true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue