xref: /freebsd/sys/contrib/openzfs/.github/workflows/scripts/qemu-4-build-vm.sh (revision 24e4dcf4ba5e9dedcf89efd358ea3e1fe5867020)
1#!/usr/bin/env bash
2
3######################################################################
4# 4) configure and build openzfs modules.  This is run on the VMs.
5#
6# Usage:
7#
8#       qemu-4-build-vm.sh OS [--enable-debug][--dkms][--patch-level NUM]
9#               [--poweroff][--release][--repo][--tarball]
10#
11# OS:           OS name like 'fedora41'
12# --enable-debug:  Build RPMs with '--enable-debug' (for testing)
13# --dkms:       Build DKMS RPMs as well
14# --patch-level NUM:    Use a custom patch level number for packages.
15# --poweroff:   Power-off the VM after building
16# --release     Build zfs-release*.rpm as well
17# --repo        After building everything, copy RPMs into /tmp/repo
18#               in the ZFS RPM repository file structure.  Also
19#               copy tarballs if they were built.
20# --tarball:    Also build a tarball of ZFS source
21######################################################################
22
23ENABLE_DEBUG=""
24DKMS=""
25PATCH_LEVEL=""
26POWEROFF=""
27RELEASE=""
28REPO=""
29TARBALL=""
30while [[ $# -gt 0 ]]; do
31  case $1 in
32    --enable-debug)
33      ENABLE_DEBUG=1
34      shift
35      ;;
36    --dkms)
37      DKMS=1
38      shift
39      ;;
40    --patch-level)
41      PATCH_LEVEL=$2
42      shift
43      shift
44      ;;
45    --poweroff)
46      POWEROFF=1
47      shift
48      ;;
49    --release)
50      RELEASE=1
51      shift
52      ;;
53    --repo)
54      REPO=1
55      shift
56      ;;
57    --tarball)
58      TARBALL=1
59      shift
60      ;;
61    *)
62      OS=$1
63      shift
64      ;;
65  esac
66done
67
68set -eu
69
70function run() {
71  LOG="/var/tmp/build-stderr.txt"
72  echo "****************************************************"
73  echo "$(date) ($*)"
74  echo "****************************************************"
75  ($@ || echo $? > /tmp/rv) 3>&1 1>&2 2>&3 | stdbuf -eL -oL tee -a $LOG
76  if [ -f /tmp/rv ]; then
77    RV=$(cat /tmp/rv)
78    echo "****************************************************"
79    echo "exit with value=$RV ($*)"
80    echo "****************************************************"
81    echo 1 > /var/tmp/build-exitcode.txt
82    exit $RV
83  fi
84}
85
86# Look at the RPMs in the current directory and copy/move them to
87# /tmp/repo, using the directory structure we use for the ZFS RPM repos.
88#
89# For example:
90# /tmp/repo/epel-testing/9.5
91# /tmp/repo/epel-testing/9.5/SRPMS
92# /tmp/repo/epel-testing/9.5/SRPMS/zfs-2.3.99-1.el9.src.rpm
93# /tmp/repo/epel-testing/9.5/SRPMS/zfs-kmod-2.3.99-1.el9.src.rpm
94# /tmp/repo/epel-testing/9.5/kmod
95# /tmp/repo/epel-testing/9.5/kmod/x86_64
96# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug
97# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug/kmod-zfs-debuginfo-2.3.99-1.el9.x86_64.rpm
98# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug/libnvpair3-debuginfo-2.3.99-1.el9.x86_64.rpm
99# /tmp/repo/epel-testing/9.5/kmod/x86_64/debug/libuutil3-debuginfo-2.3.99-1.el9.x86_64.rpm
100# ...
101function copy_rpms_to_repo {
102  # Pick a RPM to query. It doesn't matter which one - we just want to extract
103  # the 'Build Host' value from it.
104  rpm=$(ls zfs-*.rpm | head -n 1)
105
106  # Get zfs version '2.2.99'
107  zfs_ver=$(rpm -qpi $rpm | awk '/Version/{print $3}')
108
109  # Get "2.1" or "2.2"
110  zfs_major=$(echo $zfs_ver | grep -Eo [0-9]+\.[0-9]+)
111
112  # Get 'almalinux9.5' or 'fedora41' type string
113  build_host=$(rpm -qpi $rpm | awk '/Build Host/{print $4}')
114
115  # Get '9.5' or '41' OS version
116  os_ver=$(echo $build_host | grep -Eo '[0-9\.]+$')
117
118  # Our ZFS version and OS name will determine which repo the RPMs
119  # will go in (regular or testing).  Fedora always gets the newest
120  # releases, and Alma gets the older releases.
121  case $build_host in
122  almalinux*)
123    case $zfs_major in
124    2.2)
125      d="epel"
126      ;;
127    *)
128      d="epel-testing"
129      ;;
130    esac
131    ;;
132  fedora*)
133    d="fedora"
134    ;;
135  esac
136
137  prefix=/tmp/repo
138  dst="$prefix/$d/$os_ver"
139
140  # Special case: move zfs-release*.rpm out of the way first (if we built them).
141  # This will make filtering the other RPMs easier.
142  mkdir -p $dst
143  mv zfs-release*.rpm $dst || true
144
145  # Copy source RPMs
146  mkdir -p $dst/SRPMS
147  cp $(ls *.src.rpm) $dst/SRPMS/
148
149  if [[ "$build_host" =~ "almalinux" ]] ; then
150    # Copy kmods+userspace
151    mkdir -p $dst/kmod/x86_64/debug
152    cp $(ls *.rpm | grep -Ev 'src.rpm|dkms|debuginfo') $dst/kmod/x86_64
153    cp *debuginfo*.rpm $dst/kmod/x86_64/debug
154  fi
155
156  if [ -n "$DKMS" ] ; then
157    # Copy dkms+userspace
158    mkdir -p $dst/x86_64
159    cp $(ls *.rpm | grep -Ev 'src.rpm|kmod|debuginfo') $dst/x86_64
160  fi
161
162  # Copy debug
163  mkdir -p $dst/x86_64/debug
164  cp $(ls *debuginfo*.rpm | grep -v kmod) $dst/x86_64/debug
165}
166
167function freebsd() {
168  extra="${1:-}"
169
170  export MAKE="gmake"
171  echo "##[group]Autogen.sh"
172  run ./autogen.sh
173  echo "##[endgroup]"
174
175  echo "##[group]Configure"
176  run ./configure \
177    --prefix=/usr/local \
178    --with-libintl-prefix=/usr/local \
179    --enable-pyzfs \
180    --enable-debuginfo $extra
181  echo "##[endgroup]"
182
183  echo "##[group]Build"
184  run gmake -j$(sysctl -n hw.ncpu)
185  echo "##[endgroup]"
186
187  echo "##[group]Install"
188  run sudo gmake install
189  echo "##[endgroup]"
190}
191
192function linux() {
193  extra="${1:-}"
194
195  echo "##[group]Autogen.sh"
196  run ./autogen.sh
197  echo "##[endgroup]"
198
199  echo "##[group]Configure"
200  run ./configure \
201    --prefix=/usr \
202    --enable-pyzfs \
203    --enable-debuginfo $extra
204  echo "##[endgroup]"
205
206  echo "##[group]Build"
207  run make -j$(nproc)
208  echo "##[endgroup]"
209
210  echo "##[group]Install"
211  run sudo make install
212  echo "##[endgroup]"
213}
214
215function rpm_build_and_install() {
216  extra="${1:-}"
217
218  # Build RPMs with XZ compression by default (since gzip decompression is slow)
219  echo "%_binary_payload w7.xzdio" >> ~/.rpmmacros
220
221  echo "##[group]Autogen.sh"
222  run ./autogen.sh
223  echo "##[endgroup]"
224
225  if [ -n "$PATCH_LEVEL" ] ; then
226    sed -i -E 's/(Release:\s+)1/\1'$PATCH_LEVEL'/g' META
227  fi
228
229  echo "##[group]Configure"
230  run ./configure --enable-debuginfo $extra
231  echo "##[endgroup]"
232
233  echo "##[group]Build"
234  run make pkg-kmod pkg-utils
235  echo "##[endgroup]"
236
237  if [ -n "$DKMS" ] ; then
238    echo "##[group]DKMS"
239    make rpm-dkms
240    echo "##[endgroup]"
241  fi
242
243  if [ -n "$REPO" ] ; then
244    echo "Skipping install since we're only building RPMs and nothing else"
245  else
246    echo "##[group]Install"
247    run sudo dnf -y --nobest install $(ls *.rpm | grep -Ev 'dkms|src.rpm')
248    echo "##[endgroup]"
249  fi
250
251  # Optionally build the zfs-release.*.rpm
252  if [ -n "$RELEASE" ] ; then
253    echo "##[group]Release"
254    pushd ~
255    sudo dnf -y install rpm-build || true
256    # Check out a sparse copy of zfsonlinux.github.com.git so we don't get
257    # all the binaries.  We just need a few kilobytes of files to build RPMs.
258    git clone --depth 1 --no-checkout \
259      https://github.com/zfsonlinux/zfsonlinux.github.com.git
260
261    cd zfsonlinux.github.com
262    git sparse-checkout set zfs-release
263    git checkout
264    cd zfs-release
265
266    mkdir -p ~/rpmbuild/{BUILDROOT,SPECS,RPMS,SRPMS,SOURCES,BUILD}
267    cp RPM-GPG-KEY-openzfs* *.repo ~/rpmbuild/SOURCES
268    cp zfs-release.spec ~/rpmbuild/SPECS/
269    rpmbuild -ba ~/rpmbuild/SPECS/zfs-release.spec
270
271    # ZFS release RPMs are built.  Copy them to the ~/zfs directory just to
272    # keep all the RPMs in the same place.
273    cp ~/rpmbuild/RPMS/noarch/*.rpm ~/zfs
274    cp ~/rpmbuild/SRPMS/*.rpm ~/zfs
275
276    popd
277    rm -fr ~/rpmbuild
278    echo "##[endgroup]"
279  fi
280
281  if [ -n "$REPO" ] ; then
282    echo "##[group]Repo"
283    copy_rpms_to_repo
284    echo "##[endgroup]"
285  fi
286}
287
288function deb_build_and_install() {
289  extra="${1:-}"
290
291  echo "##[group]Autogen.sh"
292  run ./autogen.sh
293  echo "##[endgroup]"
294
295  echo "##[group]Configure"
296  run ./configure \
297    --prefix=/usr \
298    --enable-pyzfs \
299    --enable-debuginfo $extra
300  echo "##[endgroup]"
301
302  echo "##[group]Build"
303  run make native-deb-kmod native-deb-utils
304  echo "##[endgroup]"
305
306  echo "##[group]Install"
307  # Do kmod install.  Note that when you build the native debs, the
308  # packages themselves are placed in parent directory '../' rather than
309  # in the source directory like the rpms are.
310  run sudo apt-get -y install $(find ../ | grep -E '\.deb$' \
311    | grep -Ev 'dkms|dracut')
312  echo "##[endgroup]"
313}
314
315function build_tarball {
316  if [ -n "$REPO" ] ; then
317    ./autogen.sh
318    ./configure --with-config=srpm
319    make dist
320    mkdir -p /tmp/repo/releases
321    # The tarball name is based off of 'Version' field in the META file.
322    mv *.tar.gz /tmp/repo/releases/
323  fi
324}
325
326# Debug: show kernel cmdline
327if [ -f /proc/cmdline ] ; then
328  cat /proc/cmdline || true
329fi
330
331# Set our hostname to our OS name and version number.  Specifically, we set the
332# major and minor number so that when we query the Build Host field in the RPMs
333# we build, we can see what specific version of Fedora/Almalinux we were using
334# to build them.  This is helpful for matching up KMOD versions.
335#
336# Examples:
337#
338# rhel8.10
339# almalinux9.5
340# fedora42
341source /etc/os-release
342 if which hostnamectl &> /dev/null ; then
343  # Fedora 42+ use hostnamectl
344  sudo hostnamectl set-hostname "$ID$VERSION_ID"
345  sudo hostnamectl set-hostname --pretty "$ID$VERSION_ID"
346else
347  sudo hostname "$ID$VERSION_ID"
348fi
349
350# save some sysinfo
351uname -a > /var/tmp/uname.txt
352
353cd $HOME/zfs
354export PATH="$PATH:/sbin:/usr/sbin:/usr/local/sbin"
355
356extra=""
357if [ -n "$ENABLE_DEBUG" ] ; then
358  extra="--enable-debug"
359fi
360
361# build
362case "$OS" in
363  freebsd*)
364    freebsd "$extra"
365    ;;
366  alma*|centos*)
367    rpm_build_and_install "--with-spec=redhat $extra"
368    ;;
369  fedora*)
370    rpm_build_and_install "$extra"
371
372    # Historically, we've always built the release tarballs on Fedora, since
373    # there was one instance long ago where we built them on CentOS 7, and they
374    # didn't work correctly for everyone.
375    if [ -n "$TARBALL" ] ; then
376        build_tarball
377    fi
378    ;;
379  debian*|ubuntu*)
380    deb_build_and_install "$extra"
381    ;;
382  *)
383    linux "$extra"
384    ;;
385esac
386
387
388# building the zfs module was ok
389echo 0 > /var/tmp/build-exitcode.txt
390
391# reset cloud-init configuration and poweroff
392if [ -n "$POWEROFF" ] ; then
393        sudo cloud-init clean --logs
394        sync && sleep 2 && sudo poweroff &
395fi
396exit 0
397