Skip to content

Commit

Permalink
add github workflow for linux with pytest and pebble
Browse files Browse the repository at this point in the history
Adds a workflow on ubuntu-latest. Required some adjustements:
- no longer use `apachectl` and call `httpd/apache2` directly
- add some more debuging when apache start/restart/stop fails
  • Loading branch information
icing committed Jan 13, 2025
1 parent d7232c9 commit e9eba34
Show file tree
Hide file tree
Showing 34 changed files with 501 additions and 375 deletions.
67 changes: 48 additions & 19 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,33 +39,62 @@ env:
CFLAGS: "-g"

jobs:
build:
linux:
name: ${{ matrix.name }}
runs-on: ubuntu-latest
timeout-minutes: 30
strategy:
fail-fast: false
matrix:
include:
build:
- name: Default
install_packages:
install_steps: pytest
install_steps: pytest pebble

steps:
- name: 'install prereqs'
run: |
sudo apt-get update -y
sudo apt-get install -y --no-install-suggests --no-install-recommends \
libtool autoconf automake pkgconf apache2 apache2-dev openssl \
libssl-dev libjansson-dev libcurl4-openssl-dev \
${{ matrix.build.install_packages }}
python3 -m venv $HOME/venv
steps:
- name: 'install prereqs'
run: |
sudo apt-get update -y
sudo apt-get install -y --no-install-suggests --no-install-recommends \
libtool autoconf automake pkgconf apache2 apache2-dev openssl \
curl nghttp2-client libssl-dev libjansson-dev libcurl4-openssl-dev \
${{ matrix.build.install_packages }}
python3 -m venv $HOME/venv
- name: 'configure'
run: |
autoreconf -fi
./configure --enable-werror
- uses: actions/checkout@v4

- name: 'build'
run: |
make V=1
- name: 'install test prereqs'
run: |
[ -x "$HOME/venv/bin/activate" ] && source $HOME/venv/bin/activate
python3 -m pip install -r test/requirements.txt
- name: setup Go
if: contains(matrix.build.install_steps, 'pebble')
uses: actions/setup-go@v5

- name: install pebble
if: contains(matrix.build.install_steps, 'pebble')
run: |
export PATH=$PATH:$HOME/go/bin
git clone --quiet --depth=1 https://github.com/letsencrypt/pebble/
cd pebble
go install ./cmd/pebble
go install ./cmd/pebble-challtestsrv
- name: 'configure'
run: |
export PATH=$PATH:$HOME/go/bin
autoreconf -fi
./configure --enable-werror
- name: 'build'
run: make V=1

- name: pytest
if: contains(matrix.build.install_steps, 'pytest')
env:
PYTEST_ADDOPTS: "--color=yes"
run: |
export PATH=$PATH:$HOME/go/bin
[ -x "$HOME/venv/bin/activate" ] && source $HOME/venv/bin/activate
pytest -v
46 changes: 30 additions & 16 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -117,24 +117,37 @@ CPPFLAGS="-I$($APXS -q includedir) -I$($APXS -q APR_INCLUDEDIR) $($APXS -q EXTRA
HTTPD_VERSION="$($APXS -q HTTPD_VERSION)"
AC_SUBST(HTTPD_VERSION)

APACHECTL="$sbindir/apachectl"
if test ! -x "$APACHECTL"; then
# rogue distros rename things! =)
APACHECTL="$sbindir/apache2ctl"
fi
AC_SUBST(APACHECTL)

if test -x "$APACHECTL"; then
DSO_MODULES="$($APACHECTL -t -D DUMP_MODULES | fgrep '(shared)'| sed 's/_module.*//g'|tr -d \\n)"
AC_SUBST(DSO_MODULES)
STATIC_MODULES="$($APACHECTL -t -D DUMP_MODULES | fgrep '(static)'| sed 's/_module.*//g'|tr -d \\n)"
AC_SUBST(STATIC_MODULES)
MPM_MODULES="mpm_event mpm_worker"
AC_SUBST(MPM_MODULES)
HTTPD="$sbindir/httpd"
if test -x "$HTTPD"; then
: # all fine
else
AC_MSG_WARN("apachectl not found in '$BINDIR', test suite will not work!")
APACHECTL=""
HTTPD="$sbindir/apache2"
if test -x "$HTTPD"; then
: # all fine
else
HTTPD=""
AC_PATH_PROG([HTTPD], [httpd])
if test -x "$HTTPD"; then
: # ok
else
HTTPD=""
AC_PATH_PROG([HTTPD], [apache2])
if test -x "$HTTPD"; then
: # ok
else
AC_MSG_ERROR([httpd/apache2 not in PATH])
fi
fi
fi
fi
AC_SUBST(HTTPD)

DSO_MODULES="$($HTTPD -t -D DUMP_MODULES | fgrep '(shared)'| sed 's/_module.*//g'|tr -d \\n)"
AC_SUBST(DSO_MODULES)
STATIC_MODULES="$($HTTPD -t -D DUMP_MODULES | fgrep '(static)'| sed 's/_module.*//g'|tr -d \\n)"
AC_SUBST(STATIC_MODULES)
MPM_MODULES="mpm_event mpm_worker"
AC_SUBST(MPM_MODULES)

# We need a JSON lib, like jansson
#
Expand Down Expand Up @@ -459,6 +472,7 @@ AC_MSG_NOTICE([summary of build options:
Install prefix: ${prefix}
APXS: ${APXS}
HTTPD-VERSION: ${HTTPD_VERSION}
HTTPD: ${HTTPD}
C compiler: ${CC} ${COMPILER_VERSION}
CFLAGS: ${CFLAGS}
WARNCFLAGS: ${WERROR_CFLAGS}
Expand Down
3 changes: 1 addition & 2 deletions test/modules/md/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,11 @@

sys.path.append(os.path.join(os.path.dirname(__file__), '../..'))

from .md_conf import HttpdConf
from .md_env import MDTestEnv
from .md_acme import MDPebbleRunner, MDBoulderRunner


def pytest_report_header(config, startdir):
def pytest_report_header(config):
env = MDTestEnv()
return "mod_md: [apache: {aversion}({prefix}), mod_{ssl}, ACME server: {acme}]".format(
prefix=env.prefix,
Expand Down
29 changes: 20 additions & 9 deletions test/modules/md/md_env.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ class MDTestSetup(HttpdTestSetup):
def __init__(self, env: 'MDTestEnv'):
super().__init__(env=env)
self.mdenv = env
self.add_modules(["watchdog", "proxy_connect", "md"])
self.add_modules(["watchdog", "proxy_connect"])
self.add_local_module("md", "src/.libs/mod_md.so")

def make(self):
super().make()
Expand Down Expand Up @@ -87,13 +88,16 @@ def is_pebble(cls) -> bool:
def lacks_ocsp(cls):
return cls.is_pebble()

A2MD_BIN = None

@classmethod
def has_a2md(cls):
d = os.path.dirname(inspect.getfile(HttpdTestEnv))
config = ConfigParser(interpolation=ExtendedInterpolation())
config.read(os.path.join(d, 'config.ini'))
bin_dir = config.get('global', 'bindir')
a2md_bin = os.path.join(bin_dir, 'a2md')
if cls.A2MD_BIN is None:
d = os.path.dirname(inspect.getfile(HttpdTestEnv))
config = ConfigParser(interpolation=ExtendedInterpolation())
config.read(os.path.join(d, 'config.ini'))
src_dir = config.get('test', 'src_dir')
a2md_bin = os.path.join(src_dir, 'src/a2md')
return os.path.isfile(a2md_bin)

def __init__(self, pytestconfig=None):
Expand All @@ -113,7 +117,7 @@ def __init__(self, pytestconfig=None):
self._acme_server_down = False
self._acme_server_ok = False

self._a2md_bin = os.path.join(self.bin_dir, 'a2md')
self._a2md_bin = os.path.join(self.src_dir, 'src/a2md')
self._default_domain = f"test1.{self.http_tld}"
self._tailscale_domain = "test.headless-chicken.ts.net"
self._store_dir = "./md"
Expand Down Expand Up @@ -309,8 +313,15 @@ def check_md(self, domain, md=None, state=-1, ca=None, protocol=None, agreement=
if md:
domain = md
path = self.store_domain_file(domain, 'md.json')
with open(path) as f:
md = json.load(f)
try:
with open(path) as f:
md = json.load(f)
except FileNotFoundError:
log.error(f"not found: {path}")
if not os.path.exists(self._store_dir):
log.error(f"md store dir not found: {self._store_dir}")
self.httpd_error_log.dump(log)
assert False
assert md
if domains:
assert md['domains'] == domains
Expand Down
2 changes: 1 addition & 1 deletion test/modules/md/test_010_store_migrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class TestStoreMigrate:
@pytest.fixture(autouse=True, scope='class')
def _class_scope(self, env):
MDConf(env).install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# install old store, start a2md list, check files afterwards
def test_md_010_000(self, env):
Expand Down
2 changes: 1 addition & 1 deletion test/modules/md/test_202_acmev2_regs.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def _class_scope(self, env, acme):
env.check_acme()
env.APACHE_CONF_SRC = "data/test_drive"
MDConf(env).install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

@pytest.fixture(autouse=True, scope='function')
def _method_scope(self, env):
Expand Down
32 changes: 16 additions & 16 deletions test/modules/md/test_300_conf_validate.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def test_md_300_001(self, env):
MDConf(env, text="""
MDomain not-forbidden.org www.not-forbidden.org mail.not-forbidden.org
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand All @@ -38,7 +38,7 @@ def test_md_300_002(self, env):
MDomain not-forbidden.org www.not-forbidden.org mail.not-forbidden.org
MDomain example2.org www.example2.org mail.example2.org
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand Down Expand Up @@ -84,7 +84,7 @@ def test_md_300_005(self, env):
MDomain example2.org www.example2.org www.example3.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand All @@ -101,7 +101,7 @@ def test_md_300_006(self, env):
MDomain example2.org www.example2.org www.example3.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand All @@ -121,7 +121,7 @@ def test_md_300_007(self, env):
ServerName www.example2.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand All @@ -144,7 +144,7 @@ def test_md_300_008(self, env):
ServerAlias example2.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand Down Expand Up @@ -186,7 +186,7 @@ def test_md_300_010(self, env):
</VirtualHost>
""")
conf.install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# test case: MDomain, misses one ServerAlias
def test_md_300_011a(self, env):
Expand Down Expand Up @@ -216,7 +216,7 @@ def test_md_300_011b(self, env):
ServerAlias test4.not-forbidden.org
</VirtualHost>
""" % env.https_port).install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# test case: MDomain does not match any vhost
def test_md_300_012(self, env):
Expand All @@ -227,7 +227,7 @@ def test_md_300_012(self, env):
ServerAlias test3.not-forbidden.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand All @@ -246,7 +246,7 @@ def test_md_300_013(self, env):
ServerName test-b.example2.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# test case: global server name as managed domain name
def test_md_300_014(self, env):
Expand All @@ -257,7 +257,7 @@ def test_md_300_014(self, env):
ServerName www.example2.org
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# test case: valid pkey specification
def test_md_300_015(self, env):
Expand All @@ -268,7 +268,7 @@ def test_md_300_015(self, env):
MDPrivateKeys RSA 3072
MDPrivateKeys RSA 4096
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# test case: invalid pkey specification
@pytest.mark.parametrize("line,exp_err_msg", [
Expand Down Expand Up @@ -355,7 +355,7 @@ def test_md_300_022(self, env):
ServerName secret.com
</VirtualHost>
""").install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
#
env.httpd_error_log.ignore_recent(
lognos = [
Expand Down Expand Up @@ -431,7 +431,7 @@ def test_md_300_026(self, env):
</VirtualHost>
""")
conf.install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'

# test case: configure more than 1 CA
@pytest.mark.parametrize("cas, should_work", [
Expand Down Expand Up @@ -493,7 +493,7 @@ def test_md_300_028(self, env):
# It works, if we only match on ServerNames
conf.add("MDMatchNames servernames")
conf.install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
env.httpd_error_log.ignore_recent(
lognos=[
"AH10040", # ServerAlias not covered
Expand Down Expand Up @@ -537,7 +537,7 @@ def test_md_300_029(self, env):
# It works, if we only match on ServerNames
conf.add("MDMatchNames servernames")
conf.install()
assert env.apache_restart() == 0
assert env.apache_restart() == 0, f'{env.apachectl_stderr}'
time.sleep(2)
assert env.apache_stop() == 0
# we need dns-01 challenge for the wildcard, which is not configured
Expand Down
Loading

0 comments on commit e9eba34

Please sign in to comment.