CI: Expand use of GitHub Actions for CI

Travis is becoming overall increasingly unreliable lately. We've already
seen that the timing sensitive tests regularly fail and thus they were
disabled.

Additionally they recently announced a new pricing model that caps the number
of minutes for Open Source projects:
https://blog.travis-ci.com/2020-11-02-travis-ci-new-billing

GitHub Actions VMs are working well, possibly allowing to use custom runners
for special tasks in the future.

In addition to this better performance its workflow configuration language
is more expressive compared to the Travis CI one. Specifically the build
matrix does not need to be specified in YAML. Instead it can be generated
ad-hoc using a script. This allows us to cleanly define the various build
configurations without having an unreadable 80 line mess where the flags
are inconsistently activated. As an example in the current Travis CI
configuration the prometheus exporter is tested together with LibreSSL 2.9.2
for whatever reason.

In addition to all the previous points the UI of Travis is not that nice.
On GitHub you are just seeing that "Travis failed" without any details which
exact job failed. This requires you to visit the slow Travis page and look
up the details there. GitHub Actions creates a single entry for each
configuration that is tested, allowing you to see the details without needing
to leave GitHub.

This new GitHub Actions workflow aims to reproduce the configurations tested
in Travis. It comes close, but is not completely there, yet. Consider this
patch a proof of concept that will evolve in the future, ideally with Ilya's
expertise.

The current configurations are as follows. Each one is tested with both gcc
and clang.
- All features disabled (no USE flags)
- All features enabled (all USE flags)
- Standalone test of each of the supported compression libraries:
  - USE_ZLIB=1
  - USE_SLZ=1
- Standalone test of various SSL libraries:
  - stock (the SSL installed by default on the VM)
  - OpenSSL 1.0.2u
  - LibreSSL 2.9.2, 3.0.2, 3.1.1
- All features enabled with ASAN (clang only)

Future additions of new tests should take care to not test unrelated stuff.
Instead a distinct configuration should be added.

Additionally there is a Mac OS test with clang and all features disabled.

Known issues:
- Apparently the git commit is not properly detected during build. The HEAD
  currently shows as 2.4-dev0.
This commit is contained in:
Tim Duesterhus 2020-07-28 23:00:35 +02:00 committed by Willy Tarreau
parent 50c03aac04
commit 288c0772e6
3 changed files with 312 additions and 0 deletions

165
.github/matrix.py vendored Normal file
View File

@ -0,0 +1,165 @@
# Copyright 2019 Ilya Shipitsin <chipitsine@gmail.com>
# Copyright 2020 Tim Duesterhus <tim@bastelstu.be>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version
# 2 of the License, or (at your option) any later version.
import json
def clean_os(os):
if os == "ubuntu-latest":
return "Ubuntu"
elif os == "macos-latest":
return "macOS"
return os.replace("-latest", "")
def clean_ssl(ssl):
return ssl.replace("_VERSION", "").lower()
def clean_compression(compression):
return compression.replace("USE_", "").lower()
def get_asan_flags(cc):
if cc == "clang":
return [
"USE_OBSOLETE_LINKER=1",
'DEBUG_CFLAGS="-g -fsanitize=address"',
'LDFLAGS="-fsanitize=address"',
'CPU_CFLAGS.generic="-O1"',
]
raise ValueError("ASAN is only supported for clang")
matrix = []
# Ubuntu
os = "ubuntu-latest"
TARGET = "linux-glibc"
for CC in ["gcc", "clang"]:
matrix.append(
{
"name": "{}, {}, no features".format(clean_os(os), CC),
"os": os,
"TARGET": TARGET,
"CC": CC,
"FLAGS": [],
}
)
matrix.append(
{
"name": "{}, {}, all features".format(clean_os(os), CC),
"os": os,
"TARGET": TARGET,
"CC": CC,
"FLAGS": [
"USE_ZLIB=1",
"USE_PCRE=1",
"USE_PCRE_JIT=1",
"USE_LUA=1",
"USE_OPENSSL=1",
"USE_SYSTEMD=1",
"USE_WURFL=1",
"WURFL_INC=contrib/wurfl",
"WURFL_LIB=contrib/wurfl",
"USE_DEVICEATLAS=1",
"DEVICEATLAS_SRC=contrib/deviceatlas",
# "USE_51DEGREES=1",
# "FIFTYONEDEGREES_SRC=contrib/51d/src/pattern",
],
}
)
for compression in ["USE_SLZ=1", "USE_ZLIB=1"]:
matrix.append(
{
"name": "{}, {}, gz={}".format(
clean_os(os), CC, clean_compression(compression)
),
"os": os,
"TARGET": TARGET,
"CC": CC,
"FLAGS": [compression],
}
)
for ssl in [
"stock",
"OPENSSL_VERSION=1.0.2u",
"LIBRESSL_VERSION=2.9.2",
"LIBRESSL_VERSION=3.0.2",
"LIBRESSL_VERSION=3.1.1",
]:
flags = ["USE_OPENSSL=1"]
if ssl != "stock":
flags.append("SSL_LIB=${HOME}/opt/lib")
flags.append("SSL_INC=${HOME}/opt/include")
matrix.append(
{
"name": "{}, {}, ssl={}".format(clean_os(os), CC, clean_ssl(ssl)),
"os": os,
"TARGET": TARGET,
"CC": CC,
"ssl": ssl,
"FLAGS": flags,
}
)
# ASAN
os = "ubuntu-latest"
CC = "clang"
TARGET = "linux-glibc"
matrix.append(
{
"name": "{}, {}, ASAN, all features".format(clean_os(os), CC),
"os": os,
"TARGET": TARGET,
"CC": CC,
"FLAGS": get_asan_flags(CC)
+ [
"USE_ZLIB=1",
"USE_PCRE=1",
"USE_PCRE_JIT=1",
"USE_LUA=1",
"USE_OPENSSL=1",
"USE_SYSTEMD=1",
"USE_WURFL=1",
"WURFL_INC=contrib/wurfl",
"WURFL_LIB=contrib/wurfl",
"USE_DEVICEATLAS=1",
"DEVICEATLAS_SRC=contrib/deviceatlas",
# "USE_51DEGREES=1",
# "FIFTYONEDEGREES_SRC=contrib/51d/src/pattern",
],
}
)
# macOS
os = "macos-latest"
TARGET = "osx"
for CC in ["clang"]:
matrix.append(
{
"name": "{}, {}, no features".format(clean_os(os), CC),
"os": os,
"TARGET": TARGET,
"CC": CC,
"FLAGS": [],
}
)
# Print matrix
print(json.dumps(matrix, indent=4, sort_keys=True))
print("::set-output name=matrix::{}".format(json.dumps({"include": matrix})))

14
.github/vtest.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
"problemMatcher": [
{
"owner": "vtest",
"pattern": [
{
"regexp": "^#(\\s+top\\s+TEST\\s+(.*)\\s+FAILED.*)",
"file": 2,
"message": 1
}
]
}
]
}

133
.github/workflows/vtest.yml vendored Normal file
View File

@ -0,0 +1,133 @@
# Copyright 2019 Ilya Shipitsin <chipitsine@gmail.com>
# Copyright 2020 Tim Duesterhus <tim@bastelstu.be>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version
# 2 of the License, or (at your option) any later version.
name: VTest
on:
push:
jobs:
# The generate-matrix job generates the build matrix using JSON output
# generated by .github/matrix.py.
generate-matrix:
name: Generate Build Matrix
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- uses: actions/checkout@v2
- name: Generate Build Matrix
id: set-matrix
run: python3 .github/matrix.py
# The Test job actually runs the tests.
Test:
name: ${{ matrix.name }}
needs: generate-matrix
runs-on: ${{ matrix.os }}
strategy:
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
fail-fast: false
env:
# Configure a short TMPDIR to prevent failures due to long unix socket
# paths.
TMPDIR: /tmp
# Force ASAN output into asan.log to make the output more readable.
ASAN_OPTIONS: log_path=asan.log
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 100
- name: Install apt dependencies
if: ${{ startsWith(matrix.os, 'ubuntu-') }}
run: |
sudo apt-get install -y \
liblua5.3-dev \
libpcre2-dev \
libsystemd-dev \
ninja-build \
socat
- name: Install brew dependencies
if: ${{ startsWith(matrix.os, 'macos-') }}
run: |
brew install socat
brew install lua
- name: Install VTest
run: |
curl -fsSL https://github.com/vtest/VTest/archive/master.tar.gz -o VTest.tar.gz
mkdir VTest
tar xvf VTest.tar.gz -C VTest --strip-components=1
make -C VTest -j$(nproc) FLAGS="-O2 -s -Wall"
sudo install -m755 VTest/vtest /usr/local/bin/vtest
- name: Install SLZ
if: ${{ contains(matrix.FLAGS, 'USE_SLZ=1') }}
run: |
curl -fsSL https://github.com/wtarreau/libslz/archive/master.tar.gz -o libslz.tar.gz
mkdir libslz
tar xvf libslz.tar.gz -C libslz --strip-components=1
make -C libslz
sudo make -C libslz install
- name: Install SSL ${{ matrix.ssl }}
if: ${{ matrix.ssl && matrix.ssl != 'stock' }}
run: env ${{ matrix.ssl }} scripts/build-ssl.sh
- name: Build WURFL
if: ${{ contains(matrix.FLAGS, 'USE_WURFL=1') }}
run: make -C contrib/wurfl
- name: Compile HAProxy with ${{ matrix.CC }}
run: |
make -j$(nproc) all \
ERR=1 \
TARGET=${{ matrix.TARGET }} \
CC=${{ matrix.CC }} \
${{ join(matrix.FLAGS, ' ') }} \
ADDLIB="-Wl,-rpath,/usr/local/lib/ -Wl,-rpath,$HOME/opt/lib/"
sudo make install
- name: Show HAProxy version
id: show-version
run: |
echo "::group::Show dynamic libraries."
if command -v ldd > /dev/null; then
# Linux
ldd $(which haproxy)
else
# macOS
otool -L $(which haproxy)
fi
echo "::endgroup::"
haproxy -vv
echo "::set-output name=version::$(haproxy -v |awk 'NR==1{print $3}')"
- name: Adjust hosts file
# This step can be removed if https://github.com/vtest/VTest/pull/24 is
# fixed.
run: |
cat /etc/hosts
sudo sed -i.bak '/::1/s/^/#/' /etc/hosts
- name: Install problem matcher for VTest
# This allows one to more easily see which tests fail.
run: echo "::add-matcher::.github/vtest.json"
- name: Run VTest for HAProxy ${{ steps.show-version.outputs.version }}
id: vtest
# sudo is required, because macOS fails due to an open files limit.
run: sudo make reg-tests REGTESTS_TYPES=default,bug,devel
- name: Show results
if: ${{ failure() }}
# The chmod / sudo is necessary due to the `sudo` while running the tests.
run: |
sudo chmod a+rX ${TMPDIR}/haregtests-*/
for folder in ${TMPDIR}/haregtests-*/vtc.*; do
printf "::group::"
cat $folder/INFO
cat $folder/LOG
echo "::endgroup::"
done
shopt -s nullglob
for asan in asan.log*; do
echo "::group::$asan"
sudo cat $asan
echo "::endgroup::"
done