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()
|