summaryrefslogtreecommitdiff
path: root/ambient-build-debian-image
blob: f3d1dfe4d1b54b25f90b9122921ece80eabfd3aa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
#!/usr/bin/python3

import argparse
import os
import shutil
import subprocess
import sys
import tempfile
import yaml


PROG = "ambient-build-debian-image"
DESC = "build virtual machine image with Debian for Ambient"
VERSION = "0.0"
CACHE = os.path.expanduser("~/.cache/ambient")
BASE_VMDB = "ambient.vmdb"
BASE_PLAYBOOK = "ambient-playbook-base.yml"


def parse_args():
    p = argparse.ArgumentParser(prog=PROG, description=DESC)

    p.add_argument(
        "--version", action="version", version=VERSION, help="show version of program"
    )

    p.add_argument(
        "--cache",
        action="store",
        help="set cache directory (default is %(default)s)",
        default=CACHE,
    )

    p.add_argument(
        "--playbook",
        action="store",
        help="extra Ansible playbook to use with vmdb to build image (default is none)",
    )

    p.add_argument(
        "--image",
        action="store",
        help="filename for resulting image (required)",
        required=True,
    )
    return p.parse_args()


def load_yaml(filename):
    with open(filename) as f:
        return yaml.safe_load(f)


def write_yaml(filename, obj):
    with open(filename, "w") as f:
        yaml.safe_dump(obj, stream=f, indent=4)


def prepare_build_files(tmp, args):
    vmdb_filename = os.path.join(tmp, "image.vmdb")
    playbook_filename = os.path.join(tmp, "playbook.yml")
    extra_playbook_filename = os.path.join(tmp, "extra.yml")

    vmdb = load_yaml(BASE_VMDB)

    if args.playbook is not None:
        vmdb["steps"].append(
            {
                # note: the value MUST be the root file system tag in the VMDB file
                "ansible": "/",
                "playbook": args.playbook,
            }
        )
        shutil.copyfile(args.playbook, extra_playbook_filename)

    write_yaml(vmdb_filename, vmdb)
    shutil.copyfile(BASE_PLAYBOOK, playbook_filename)

    return vmdb_filename


def build_image(tmp, vmdb, tarball, image):
    raw = os.path.join(tmp, "image.img")
    log = os.path.join(tmp, "log")

    # Build image.
    p = subprocess.run(
        ["vmdb2", vmdb, "--output", raw, "--rootfs-tarball", tarball, "--log", log],
        capture_output=True,
    )
    if p.returncode != 0:
        with open(log, "r") as f:
            log = f.read()
        sys.stderr.write(f"{log}\nERROR: failed to build image\n")
        sys.exit(1)

    # Convert built image from raw to QCOW2 format.
    p = subprocess.run(
        ["qemu-img", "convert", "-f", "raw", "-O", "qcow2", raw, image],
        capture_output=True,
    )
    if p.returncode != 0:
        sys.stderr.write(f"{p.stderr}\nERROR: failed to convert image to QCOW2\n")
        sys.exit(1)


def main():
    args = parse_args()
    tarball = os.path.join(args.cache, "ambient.tar.gz")
    tmp = tempfile.mkdtemp()

    try:
        vmdb = prepare_build_files(tmp, args)
    except Exception as e:
        sys.stderr.write("ERROR: failed to create build files: {e}\n")
        shutil.rmtree(tmp)
        sys.exit(1)

    try:
        build_image(tmp, vmdb, tarball, args.image)
    except Exception as e:
        sys.stderr.write(f"ERROR: failed to build image: {e}\n")
        shutil.rmtree(tmp)
        sys.exit(1)


main()