From 0cb66a44d09775301f7db3b8b9706696661ba301 Mon Sep 17 00:00:00 2001 From: Georg Pfuetzenreuter Date: Jan 04 2024 22:10:16 +0000 Subject: test_nginx: render one job per role Instead of testing one nginx related role at a time, generate individual CI jobs to facilitate parallel execution. Signed-off-by: Georg Pfuetzenreuter --- diff --git a/.gitlab-ci.templates/test_nginx.jinja b/.gitlab-ci.templates/test_nginx.jinja new file mode 100644 index 0000000..ef51849 --- /dev/null +++ b/.gitlab-ci.templates/test_nginx.jinja @@ -0,0 +1,20 @@ +.test_nginx: + image: registry.opensuse.org/opensuse/infrastructure/containers/heroes-salt-testing-nginx:latest + stage: test + before_script: + - bin/prepare_test_env.sh -g -s + - bin/get_formulas.py -c -d /srv/formula -s --clone-from 'https://gitlab.infra.opensuse.org/saltstack-formulas' --clone-branch production -f nginx + script: bin/test_nginx.sh + tags: + - docker + artifacts: + when: always + paths: + - '*.txt' + +{% for role in roles %} +test_nginx_{{ role }}: + extends: + - .test_nginx + script: bin/test_nginx.sh {{ role }} +{% endfor %} diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index db5a491..05540e2 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -49,22 +49,12 @@ test_haproxy: # - salt/profile/proxy/* # - salt/role/proxy* -test_nginx: - extends: - - .test_common - - .test_artifacts - image: registry.opensuse.org/opensuse/infrastructure/containers/heroes-salt-testing-nginx:latest - before_script: - - bin/prepare_test_env.sh -g -s - - bin/get_formulas.py -c -d /srv/formula -s --clone-from 'https://gitlab.infra.opensuse.org/saltstack-formulas' --clone-branch production -f nginx - script: bin/test_nginx.sh - # Dynamically generated jobs prepare_includes: script: bin/render_gitlab_ci_includes.py -w artifacts: paths: - - .gitlab-ci.includes/test_highstate.yml + - .gitlab-ci.includes/*.yml test_highstate: needs: @@ -75,6 +65,14 @@ test_highstate: job: prepare_includes strategy: depend +test_nginx: + needs: + - prepare_includes + trigger: + include: + - artifact: .gitlab-ci.includes/test_nginx.yml + job: prepare_includes + strategy: depend deploy_job: stage: deploy diff --git a/bin/render_gitlab_ci_includes.py b/bin/render_gitlab_ci_includes.py index e0c6123..650f690 100755 --- a/bin/render_gitlab_ci_includes.py +++ b/bin/render_gitlab_ci_includes.py @@ -1,7 +1,6 @@ #!/usr/bin/python3 """ -Script for generating a .gitlab-ci.yml drop-in for test_highstate -(can be expanded for other jobs if needed) +Script for rending .gitlab-ci.yml drop-ins based on available Salt roles Copyright (C) 2023 openSUSE contributors Copyright (C) 2023 Georg Pfuetzenreuter @@ -19,13 +18,19 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . """ -from get_roles import get_roles +from get_roles import get_roles, get_roles_including from argparse import ArgumentParser from jinja2 import Template from pathlib import Path import sys +enabled_templates = [ + 'highstate', + 'nginx' +] + +indir = '.gitlab-ci.templates' outdir = '.gitlab-ci.includes' argp = ArgumentParser(description='Generate .gitlab-ci.yml include files based on Salt roles') @@ -37,16 +42,22 @@ if not args.p and not args.w: argp.print_help() sys.exit(1) -# Render include with role based test_highstate chunks -with open('.gitlab-ci.templates/test_highstate.jinja', 'r') as j2: - template = Template(j2.read()) +template = {} +render = {} + +for entry in enabled_templates: + with open(f'{indir}/test_{entry}.jinja', 'r') as j2: + template[entry] = Template(j2.read()) -rendered = template.render(roles=get_roles()) + if entry == 'highstate': + render[entry] = template[entry].render(roles=get_roles()) + else: + render[entry] = template[entry].render(roles=get_roles_including(entry)) -if args.p: - print(rendered) + if args.p: + print(render[entry]) -if args.w: - Path(f'{outdir}').mkdir(exist_ok=True) - with open(f'{outdir}/test_highstate.yml', 'w') as fh: - fh.write(rendered) + if args.w: + Path(f'{outdir}').mkdir(exist_ok=True) + with open(f'{outdir}/test_{entry}.yml', 'w') as fh: + fh.write(render[entry]) diff --git a/bin/test_nginx.sh b/bin/test_nginx.sh index 67f60a8..7048bf9 100755 --- a/bin/test_nginx.sh +++ b/bin/test_nginx.sh @@ -6,31 +6,13 @@ rpm -qa --qf '%{name}\n' | sort > /tmp/packages-before [[ $(whoami) == 'root' ]] || { echo 'Please run this script as root'; exit 1; } -# systemctl refuses to work in a container, but is needed by service.running. Replace it with /usr/bin/true to avoid useless error messages +# using a container without systemd, but systemd is needed by service.running. replace it with /usr/bin/true to avoid useless error messages. ( cd /usr/bin/ ; ln -sf true systemctl ) source bin/get_colors.sh -rpm -q nginx salt salt-master - -IDFILE="pillar/id/$(hostname).sls" -IDFILE_BASE="$IDFILE.base.sls" -sed -i -e '/virtual/d' /etc/salt/grains -cp "$IDFILE" "$IDFILE_BASE" - -reset_nginx() { - cp "$IDFILE_BASE" "$IDFILE" - rm -rf /etc/nginx - cp -a /etc/nginx_orig /etc/nginx - printf "roles:\n- $role" >> "$IDFILE" -} - -reset_ip() { - # Reset the grains-retrieved IPs to 127.0.0.1, as `nginx -t` actually tries - # to bind to any configured listen IP - - sed -i -e "s/{{ ip4_.* }}/127.0.0.1/g" pillar/role/$role.sls -} +role="$1" +IDFILE="pillar/id/$HOSTNAME.sls" create_fake_certs() { # We are replacing both the cert/key pair because: @@ -59,7 +41,7 @@ create_fake_certs() { } touch_includes() { - case "$1" in + case "$role" in mailman3) touch /etc/nginx/mails.rewritemap touch /etc/nginx/lists.rewritemap @@ -77,80 +59,79 @@ touch_includes() { esac; } -cp -a /etc/nginx /etc/nginx_orig - -for role in $(bin/get_roles.py); do - rolestatus=0 - sls_role="salt/role/${role/./\/}.sls" - out="$role.txt" - if grep nginx "$sls_role" > /dev/null; then - echo "START OF $role" > "$out" - echo_INFO "Testing role: $role" - reset_nginx - reset_ip - if grep -q profile "$sls_role" +rolestatus=0 +sls_role="salt/role/${role/./\/}.sls" +out="$role.txt" +echo "START OF $role" > "$out" +echo_INFO "Testing role: $role" + +printf "roles:\n- $role" >> "$IDFILE" + +# Reset the grains-retrieved IPs to 127.0.0.1, as `nginx -t` actually tries +# to bind to any configured listen IP +sed -i -e "s/{{ ip4_.* }}/127.0.0.1/g" pillar/role/$role.sls + +if grep -q profile "$sls_role" +then + #for profile in "$(grep -h '\- profile' $sls_role | yq -o t)" // to-do: add yq to container + for profile in $(grep -h '\- profile' $sls_role | sed 's/^\s\+ -//' | tr '\n' ' ') + do + if [ ! "$profile" == 'profile.web.server.nginx' ] then - #for profile in "$(grep -h '\- profile' $sls_role | yq -o t)" // to-do: add yq to container - for profile in $(grep -h '\- profile' $sls_role | sed 's/^\s\+ -//' | tr '\n' ' ') - do - if [ ! "$profile" == 'profile.web.server.nginx' ] - then - dir_profile="${profile//./\/}" - if [ -f "salt/$dir_profile/nginx.sls" ] - then - state="$profile.nginx" - elif [ -f "salt/${dir_profile%/*}/nginx.sls" ] - then - state="${profile%.*}.nginx" - fi - if [ -n "$state" ] - then - echo "Applying $state ..." >> "$out" - salt-call --local state.apply "$state" >> "$out" || rolestatus=1 - echo >> "$out" - unset state - break - fi - fi - done - fi - echo 'Applying nginx ...' >> "$out" - salt-call --local state.apply nginx >> "$out" || rolestatus=1 - create_fake_certs - touch_includes $role - - printf '\nTesting configuration ...\n' >> "$out" - mispipe 'nginx -tq' "tee -a $out" || rolestatus=1 - - printf '\nDumping configuration ...\n' >> "$out" - nginx -T >> "$out" - - # make sure all vhost config files are named *.conf (without that suffix, they get ignored) - for file in /etc/nginx/vhosts.d/* ; do - test "$file" == "/etc/nginx/vhosts.d/*" && continue # skip loop if no file exists in vhosts.d/ - echo "$file" | grep -q '\.conf$' || { - echo "ERROR: $file is not named *.conf" - rolestatus=1 - } - done - - if test $rolestatus = 0; then - echo_PASSED - else - echo_FAILED - head -n1000 /etc/nginx/vhosts.d/* - echo "### end of /etc/nginx/vhosts.d/* for role $role" - STATUS=1 + dir_profile="${profile//./\/}" + if [ -f "salt/$dir_profile/nginx.sls" ] + then + state="$profile.nginx" + elif [ -f "salt/${dir_profile%/*}/nginx.sls" ] + then + state="${profile%.*}.nginx" + fi + if [ -n "$state" ] + then + echo "Applying $state ..." >> "$out" + salt-call --local state.apply "$state" >> "$out" || rolestatus=1 + echo >> "$out" + unset state + break + fi fi - echo - echo "END OF $role" >> "$out" - fi + done +fi + +echo 'Applying nginx ...' >> "$out" +salt-call --local state.apply nginx >> "$out" || rolestatus=1 +create_fake_certs +touch_includes $role + +printf '\nTesting configuration ...\n' >> "$out" +mispipe 'nginx -tq' "tee -a $out" || rolestatus=1 + +printf '\nDumping configuration ...\n' >> "$out" +nginx -T >> "$out" + +# make sure all vhost config files are named *.conf (without that suffix, they get ignored) +for file in /etc/nginx/vhosts.d/* ; do + test "$file" == "/etc/nginx/vhosts.d/*" && continue # skip loop if no file exists in vhosts.d/ + echo "$file" | grep -q '\.conf$' || { + echo "ERROR: $file is not named *.conf" + rolestatus=1 + } done -rpm -qa --qf '%{name}\n' | sort > /tmp/packages-after +if test $rolestatus = 0; then + echo_PASSED +else + echo_FAILED + head -n1000 /etc/nginx/vhosts.d/* + echo "### end of /etc/nginx/vhosts.d/* for role $role" + STATUS=1 +fi +echo +echo "END OF $role" >> "$out" -diff -U0 /tmp/packages-before /tmp/packages-after || echo '=== The packages listed above were installed by one of the roles. Consider to add them to the docker image to speed up this test.' +rpm -qa --qf '%{name}\n' | sort > /tmp/packages-after +diff -U0 /tmp/packages-before /tmp/packages-after || echo '=== The packages listed above were installed by one of the roles. Consider to add them to the container image to speed up this test.' exit $STATUS