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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
|
#! /bin/sh
# Auto-install OpenBSD/amd64 7.3 on QEMU.
#
# First published at https://www.skreutz.com/posts/autoinstall-openbsd-on-qemu/
# on 22 July 2020.
#
# Copyright (c) 2020 Stefan Kreutz <mail@skreutz.com>
#
# Permission to use, copy, modify, and distribute this software for any purpose
# with or without fee is hereby granted, provided that the above copyright
# notice and this permission notice appear in all copies.
#
# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
# OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
# PERFORMANCE OF THIS SOFTWARE.
set -o errexit
set -o nounset
# Trusted HTTPS OpenBSD mirror to fetch the base public key from.
HTTPS_MIRROR="${HTTPS_MIRROR-https://ftp.openbsd.org/pub/OpenBSD/}"
# Untrusted rsync OpenBSD mirror.
RSYNC_MIRROR="${RSYNC_MIRROR-rsync://mirror.leaseweb.com/openbsd/}"
# File name of the disk image.
DISK_FILE="${DISK_FILE-disk.qcow2}"
# Size of the disk image.
DISK_SIZE="${DISK_SIZE-64G}"
# Number of virtual CPUs.
CPU_COUNT="${CPU_COUNT-$(grep -c ^processor /proc/cpuinfo)}"
# Size of virtual memory.
MEMORY_SIZE="${MEMORY_SIZE-4G}"
# File name of the public SSH key to authorize.
SSH_KEY="${SSH_KEY-${HOME}/.ssh/id_rsa.pub}"
# Check required commands.
for cmd in curl qemu-img qemu-system-x86_64 rsync signify socat ssh
do
if ! command -v "${cmd}" >/dev/null
then
( >&2 printf "command not found: %s\\n" "${cmd}" )
exit 1
fi
done
# Fetch base public key from trusted HTTPS mirror.
mkdir -p mirror/pub/OpenBSD/7.3
if [ ! -e mirror/pub/OpenBSD/7.3/openbsd-73-base.pub ]
then
curl \
--silent \
--output mirror/pub/OpenBSD/7.3/openbsd-73-base.pub \
"${HTTPS_MIRROR}7.3/openbsd-73-base.pub"
printf "Fetched base public key from %s\\n" "${HTTPS_MIRROR}"
fi
# Fetch kernel, PXE bootstrap program, and file sets from untrusted rsync
# mirror.
if [ ! -d mirror/pub/OpenBSD/7.3/amd64 ]
then
mkdir -p tmp
printf "Fetching installation files ...\\n"
rsync --archive --files-from=- --quiet \
"${RSYNC_MIRROR}7.3/amd64/" \
tmp/ \
<< EOF
SHA256.sig
base73.tgz
bsd
bsd.mp
bsd.rd
comp73.tgz
game73.tgz
man73.tgz
pxeboot
xbase73.tgz
xfont73.tgz
xserv73.tgz
xshare73.tgz
EOF
( cd tmp && signify -C -q \
-p ../mirror/pub/OpenBSD/7.3/openbsd-73-base.pub \
-x SHA256.sig \
-- bsd bsd.* pxeboot *73.tgz )
mv tmp mirror/pub/OpenBSD/7.3/amd64
printf "Fetched kernel, PXE bootstrap program, and file sets from %s\\n" "${RSYNC_MIRROR}"
fi
# Create autoinstall(8) configuration if not exists.
if [ ! -e mirror/install.conf ]
then
cat << EOF > mirror/install.conf
Change the default console to com0 = yes
Which speed should com0 use = 115200
System hostname = openbsd
Password for root = *************
Allow root ssh login = no
Setup a user = puffy
Password for user = *************
Public ssh key for user = $( cat "${SSH_KEY}" )
What timezone are you in = UTC
Location of sets = http
HTTP Server = 10.0.2.2
Unable to connect using https. Use http instead = yes
URL to autopartitioning template for disklabel = http://10.0.2.2/disklabel
Set name(s) = site73.tgz
Checksum test for site73.tgz failed. Continue anyway = yes
Unverified sets: site73.tgz. Continue without verification = yes
EOF
printf "Created example response file for autoinstall(8) at ./mirror/install.conf\\n"
fi
# Create disklabel(8) configuration if not exists.
# Assume disk size of at least 54G.
if [ ! -e mirror/disklabel ]
then
cat << EOF > mirror/disklabel
/ 1G
swap 8G
/tmp 4G
/var 4G
/usr 6G
/usr/X11R6 1G
/usr/local 20G
/usr/src 3G
/usr/obj 6G
/home 1G-*
EOF
printf "Created example disklabel(8) template at ./mirror/disklabel.conf\\n"
fi
# Create site-specific file set if not exists.
if [ ! -d site ]
then
mkdir site
cat << EOF > site/install.site
#! /bin/ksh
set -o errexit
# Reset OpenBSD mirror server used by pkg_add(1) and other commands.
echo "https://cdn.openbsd.org/pub/OpenBSD" > /etc/installurl
# Permit user group wheel to run any command as root without entering their
# password using doas(1).
echo "permit nopass keepenv :wheel" > /etc/doas.conf
# Patch the base system on the first boot.
#echo "syspatch && shutdown -r now" >> /etc/rc.firsttime
EOF
chmod +x site/install.site
printf "Created example site-specific file set at ./site\\n"
fi
# Package site-specific file set if not exists or changed.
site_dir_changed="$( find site -exec stat -c %Y {} \; | sort -r | head -n 1 )"
if [ ! -e mirror/pub/OpenBSD/7.3/amd64/site73.tgz ] || [ "$( stat -c %Y mirror/pub/OpenBSD/7.3/amd64/site73.tgz )" -lt "${site_dir_changed}" ]
then
rm -f mirror/pub/OpenBSD/7.3/amd64/site73.tgz
( cd site && tar -czf ../mirror/pub/OpenBSD/7.3/amd64/site73.tgz . )
( cd mirror/pub/OpenBSD/7.3/amd64 && ls -l > index.txt )
fi
# Create TFTP directory if not exists.
if [ ! -d tftp ]
then
mkdir tftp
ln -s ../mirror/pub/OpenBSD/7.3/amd64/pxeboot tftp/auto_install
ln -s ../mirror/pub/OpenBSD/7.3/amd64/bsd.rd tftp/bsd.rd
mkdir tftp/etc
cat << EOF > tftp/etc/boot.conf
stty com0 115200
set tty com0
boot tftp:/bsd.rd
EOF
printf "Created example boot(8) configuration at ./tftp/etc/boot.conf\\n"
fi
# Remove existing disk image if configuration changed.
if [ -e "${DISK_FILE}" ]
then
vm_created="$( stat -c %W "${DISK_FILE}" )"
for f in mirror/install.conf mirror/disklabel mirror/pub/OpenBSD/7.3/amd64/site73.tgz tftp/etc/boot.conf
do
if [ "${vm_created}" -lt "$( stat -c %Y "$f" )" ]
then
printf "Re-creating virtual machine due to changed configuration: %s\\n" "$f"
rm "${DISK_FILE}"
fi
done
fi
# Create disk image if not exists.
if [ ! -e "${DISK_FILE}" ]
then
qemu-img create -q -f qcow2 "${DISK_FILE}" "${DISK_SIZE}"
printf "Created %s copy-on-write disk image at %s\\n" "${DISK_SIZE}" "${DISK_FILE}"
fi
# Wait until ./mirror is served at http://127.0.0.1/.
while [ ! "$( curl --silent --location --write-out '%{http_code}\n' --output /dev/null http://127.0.0.1/install.conf )" = 200 ]
do
( >&2 printf "Please serve the directory ./mirror at http://127.0.0.1/\n" )
sleep 5
done
# Auto-install OpenBSD.
# TODO: Forward host (10.0.2.2) port 80 to host port 8080, and adapt the above check
printf "Starting virtual machine ...\\n"
qemu-system-x86_64 \
-enable-kvm \
-smp "cpus=${CPU_COUNT}" \
-m "${MEMORY_SIZE}" \
-drive "file=${DISK_FILE},media=disk,if=virtio" \
-device e1000,netdev=n1 \
-netdev "user,id=n1,hostname=openbsd-vm,tftp=tftp,bootfile=auto_install,hostfwd=tcp::2222-:22" \
-nographic
|