summaryrefslogtreecommitdiff
path: root/autoinstall-openbsd-on-qemu
blob: d71a3dc1daa93984e018bd239397c292272d981d (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
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
#! /bin/sh

# Auto-install OpenBSD/amd64 6.7 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://ftp.halifax.rwth-aachen.de/openbsd/}"

# File name of the disk image.
DISK_FILE="${DISK_FILE-disk.qcow2}"

# Size of the disk image.
DISK_SIZE="${DISK_SIZE-24G}"

# Number of virtual CPUs.
CPU_COUNT="${CPU_COUNT-4}"

# 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/6.7
if [ ! -e mirror/pub/OpenBSD/6.7/openbsd-67-base.pub ]
then
  curl \
    --silent \
    --output mirror/pub/OpenBSD/6.7/openbsd-67-base.pub \
    "${HTTPS_MIRROR}6.7/openbsd-67-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/6.7/amd64 ]
then
  mkdir -p tmp
  printf "Fetching installation files ...\\n"
  rsync --archive --files-from=- --quiet \
    "${RSYNC_MIRROR}6.7/amd64/" \
    tmp/ \
    << EOF
SHA256.sig
base67.tgz
bsd
bsd.mp
bsd.rd
comp67.tgz
game67.tgz
man67.tgz
pxeboot
xbase67.tgz
xfont67.tgz
xserv67.tgz
xshare67.tgz
EOF
  ( cd tmp && signify -C -q \
      -p ../mirror/pub/OpenBSD/6.7/openbsd-67-base.pub \
      -x SHA256.sig \
      -- bsd bsd.* pxeboot *67.tgz )
  mv tmp mirror/pub/OpenBSD/6.7/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.1
Unable to connect using https. Use http instead = yes
URL to autopartitioning template for disklabel = http://10.0.2.1/disklabel
Set name(s) = site67.tgz
Checksum test for site67.tgz failed. Continue anyway = yes
Unverified sets: site67.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.
if [ ! -e mirror/disklabel ]
then
  cat << EOF > mirror/disklabel
/            2G
swap         8G
/tmp         1G
/var         1G
/usr         2G
/usr/X11R6 500M
/usr/local   4G
/usr/src     1M
/usr/obj     1M
/home        4G
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/6.7/amd64/site67.tgz ] || [ "$( stat -c %Y mirror/pub/OpenBSD/6.7/amd64/site67.tgz )" -lt "${site_dir_changed}" ]
then
  rm -f mirror/pub/OpenBSD/6.7/amd64/site67.tgz
  ( cd site && tar -czf ../mirror/pub/OpenBSD/6.7/amd64/site67.tgz . )
  ( cd mirror/pub/OpenBSD/6.7/amd64 && ls -l > index.txt )
fi

# Create TFTP directory if not exists.
if [ ! -d tftp ]
then
  mkdir tftp
  ln -s ../mirror/pub/OpenBSD/6.7/amd64/pxeboot tftp/auto_install
  ln -s ../mirror/pub/OpenBSD/6.7/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/6.7/amd64/site67.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:8080/.
while [ ! "$( curl --silent --location --write-out '%{http_code}\n' --output /dev/null http://127.0.0.1:8080/install.conf )" = 200 ]
do
  ( >&2 printf "Please serve the directory ./mirror at http://127.0.0.1:8080/\n" )
  sleep 5
done

# Auto-install OpenBSD.
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-server-name=10.0.2.1,tftp=tftp,bootfile=auto_install,hostfwd=tcp::2222-:22,guestfwd=tcp:10.0.2.1:80-cmd:socat STDIO TCP4:127.0.0.1:8080" \
  -nographic
Generated by cgit. See skreutz.com for my tech blog and contact information.