debian-forge-composer/tools/gen-user-data
Lars Karlitski 857570980d tools: add deploy-qemu and gen-user-data
tools/gen-user-data generates a cloud-init user-data file from a
configuration directory. It is mostly useful to embed files in the
user-data.

tools/deploy-qemu uses above tool to make a user-data file and spins up
a virtual machine with it. This is useful to locally run, test, and
debug osbuild-composer.

A simple user-data directory for running tests locally is included in
tests/deploy-user-data. It expects a repository with osbuild-composer
rpms to be served on the host's port 8000.
2020-10-07 11:51:33 +02:00

75 lines
2.4 KiB
Python
Executable file

#!/usr/bin/python3
"""
gen-user-data
This tool generates a cloud-config user-data file from a directory containing
configuration. Its main purpose is to make it easy to include files in the
user-data, which need to be encoded in base64.
It writes the assembled user-data to standard out.
The configuration directory may contain:
* user-data.yml -- a base user-data. Anything that exists in this file will be
transferred as-is. Any additional configuration is appended
to already existing configuration.
* files/ -- a directory containing additional files to include. The
file's path on the target system mirrors its path relative
to this directore (`files/etc/hosts` → `/etc/hosts`). Its
permissions are copied over, but the owner will always be
root:root. Empty directories are ignored.
The `python3-pyyaml` package is required to run this tool.
"""
import argparse
import base64
import os
import stat
import sys
import yaml
def octal_mode_string(mode):
"""Convert stat.st_mode to the format cloud-init expects.
cloud-init's write_files plugin expects file permissions in the format
returned by python2's oct() function, for example '0644'. In python3, oct()
returns a string in the new octal notation, '0o644'.
"""
return "0" + oct(stat.S_IMODE(mode))[2:]
def main():
p = argparse.ArgumentParser(description="Generate cloud-config user-data")
p.add_argument("configdir", metavar="CONFIGDIR", help="input directory")
args = p.parse_args()
try:
with open(f"{args.configdir}/user-data.yml") as f:
userdata = yaml.load(f, Loader=yaml.SafeLoader)
except FileNotFoundError:
userdata = {}
filesdir = f"{args.configdir}/files"
for directory, dirs, files in os.walk(filesdir):
for name in files:
path = f"{directory}/{name}"
with open(path, "rb") as f:
content = base64.b64encode(f.read()).decode("utf-8")
userdata.setdefault("write_files", []).append({
"path": "/" + os.path.relpath(path, filesdir),
"encoding": "b64",
"content": content,
"permissions": octal_mode_string(os.lstat(path).st_mode)
})
sys.stdout.write("#cloud-config\n")
yaml.dump(userdata, sys.stdout, Dumper=yaml.SafeDumper)
if __name__ == "__main__":
sys.exit(main())