Blame stages/org.osbuild.first-boot

Packit a20ca0
#!/usr/bin/python3
Packit a20ca0
"""
Packit a20ca0
Execute commands on first-boot
Packit a20ca0
Packit a20ca0
Sequentially execute a list of commands on first-boot / instantiation.
Packit a20ca0
Packit a20ca0
This stage uses a logic similar to systemd's first-boot to execute a given
Packit a20ca0
script only the first time the image is booted.
Packit a20ca0
Packit a20ca0
An empty flag file /etc/osbuild-first-boot is written to /etc and a systemd
Packit a20ca0
service is enabled that is only run when the file exits, and will remove it
Packit a20ca0
before executing the given commands.
Packit a20ca0
Packit a20ca0
If the flag-file cannot be removed, the service fails without executing
Packit a20ca0
any further first-boot commands.
Packit a20ca0
"""
Packit a20ca0
Packit a20ca0
Packit a20ca0
import os
Packit a20ca0
import sys
Packit a20ca0
Packit Service 2d981f
import osbuild.api
Packit Service 2d981f
Packit Service 2d981f
Packit a20ca0
SCHEMA = """
Packit a20ca0
"additionalProperties": false,
Packit a20ca0
"required": ["commands"],
Packit a20ca0
"properties": {
Packit a20ca0
  "commands": {
Packit a20ca0
    "type": "array",
Packit a20ca0
    "description": "The command lines to execute",
Packit a20ca0
    "items": {
Packit a20ca0
      "type": "string"
Packit a20ca0
    }
Packit a20ca0
  },
Packit a20ca0
  "wait_for_network": {
Packit a20ca0
    "type": "boolean",
Packit a20ca0
    "description": "Wait for the network to be up before executing",
Packit a20ca0
    "default": false
Packit a20ca0
  }
Packit a20ca0
}
Packit a20ca0
"""
Packit a20ca0
Packit Service 2d981f
Packit a20ca0
def add_first_boot(tree, commands, wait_for_network):
Packit a20ca0
    if wait_for_network:
Packit a20ca0
        network = """Wants=network-online.target
Packit a20ca0
After=network-online.target"""
Packit a20ca0
    else:
Packit a20ca0
        network = ""
Packit a20ca0
Packit a20ca0
    execs = "\n"
Packit a20ca0
    for command in commands:
Packit a20ca0
        execs += f"ExecStart={command}\n"
Packit a20ca0
Packit a20ca0
    service = f"""[Unit]
Packit a20ca0
Description=OSBuild First Boot Service
Packit a20ca0
ConditionPathExists=/etc/osbuild-first-boot
Packit a20ca0
{network}
Packit a20ca0
Packit a20ca0
[Service]
Packit a20ca0
Type=oneshot
Packit a20ca0
{execs}"""
Packit a20ca0
Packit a20ca0
    os.makedirs(f"{tree}/usr/lib/systemd/system/default.target.wants", exist_ok=True)
Packit a20ca0
    with open(f"{tree}/usr/lib/systemd/system/osbuild-first-boot.service", "w") as f:
Packit a20ca0
        f.write(service)
Packit a20ca0
    os.symlink("../osbuild-first-boot.service",
Packit a20ca0
               f"{tree}/usr/lib/systemd/system/default.target.wants/osbuild-first-boot.service")
Packit a20ca0
Packit a20ca0
    os.makedirs(f"{tree}/etc", exist_ok=True)
Packit a20ca0
    open(f"{tree}/etc/osbuild-first-boot", 'a').close()
Packit a20ca0
Packit Service 2d981f
Packit a20ca0
def main(tree, options):
Packit a20ca0
    commands = options["commands"]
Packit a20ca0
    wait_for_network = options.get("wait_for_network", False)
Packit a20ca0
Packit a20ca0
    commands = ["/usr/bin/rm /etc/osbuild-first-boot"] + commands
Packit a20ca0
Packit a20ca0
    add_first_boot(tree, commands, wait_for_network)
Packit a20ca0
Packit a20ca0
    return 0
Packit a20ca0
Packit a20ca0
Packit a20ca0
if __name__ == '__main__':
Packit Service 2d981f
    args = osbuild.api.arguments()
Packit a20ca0
    r = main(args["tree"], args["options"])
Packit a20ca0
    sys.exit(r)