Skip to content

Commit 092ed6d

Browse files
committed
ci(podman): add state tests in simple container
1 parent 5e2e2e3 commit 092ed6d

File tree

9 files changed

+354
-0
lines changed

9 files changed

+354
-0
lines changed

.github/workflows/test.yaml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
name: CI
2+
3+
on: [push, pull_request, workflow_dispatch]
4+
5+
jobs:
6+
test:
7+
runs-on: ubuntu-latest
8+
strategy:
9+
matrix:
10+
img:
11+
- opensuse.leap
12+
- debian.11
13+
steps:
14+
- uses: actions/checkout@v2
15+
- name: Test
16+
run: |
17+
cd t && \
18+
make test_container
19+
env:
20+
T_IMAGE: ${{ matrix.img }}

t/01-smoke-server.sh

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#!lib/test-in-container-systemd.sh mariadb
2+
3+
set -ex
4+
5+
salt-call --local state.apply 'mysql'
6+
salt-call --local state.apply 'mysql.remove_test_database'
7+
8+
mysql -e 'select user(), current_user(), version()'
9+
10+
service mysql status
11+
12+
echo success

t/02-smoke-client.sh

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!lib/test-in-container-systemd.sh mariadb-client
2+
3+
set -ex
4+
5+
#########################
6+
# workaround for https://github.com/saltstack-formulas/mysql-formula/issues/267
7+
( grep -qi debian /etc/*release && mkdir -p /etc/mysql ) || \
8+
( grep -qi suse /etc/*release && mkdir -p /etc/my.cnf.d ) || \
9+
:
10+
#########################
11+
12+
salt-call --local state.apply 'mysql.client'
13+
14+
mariadb -V || mysql -V
15+
16+
# check mysqld service is not installed
17+
rc=0
18+
service mysql status || rc=$?
19+
test $rc -gt 0
20+
21+
rc=0
22+
service mysql status || rc=$?
23+
test $rc -gt 0
24+
25+
rc=0
26+
service mariadb status || rc=$?
27+
test $rc -gt 0
28+
29+
echo success

t/10-password.sh

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#!lib/test-in-container-systemd.sh mariadb
2+
3+
set -ex
4+
5+
# hack the pillar
6+
mkdir -p /srv/pillar
7+
echo "
8+
mysql:
9+
server:
10+
mysqld:
11+
max_allowed_packet: 1111040
12+
database:
13+
- testdb
14+
user:
15+
myuser1:
16+
password: 'mypass123'
17+
host: localhost
18+
databases:
19+
- database: testdb
20+
grants: ['all']
21+
" > /srv/pillar/testdata.sls
22+
23+
echo '
24+
{{ saltenv }}:
25+
"*":
26+
- testdata
27+
' >> /srv/pillar/top.sls
28+
29+
30+
salt-call --local pillar.get mysql:user:myuser1:password
31+
salt-call --local pillar.item mysql:user:myuser1:password | grep mypass123
32+
33+
pass=$(echo $(salt-call --local pillar.get mysql:user:myuser1:password) | tail -n 1 | grep -Eo '[^ ]+$')
34+
test "$pass" == mypass123
35+
36+
salt-call --local state.apply 'mysql'
37+
salt-call --local state.apply 'mysql.remove_test_database'
38+
39+
set -a
40+
shopt -s expand_aliases
41+
alias sql="mariadb -h 127.0.0.1 -umyuser1 -p$pass -e"
42+
(
43+
44+
sql 'select user(), current_user(), version()'
45+
46+
packet="$(sql 'show variables like "max_allowed_packet"' -Nb)"
47+
test 1111040 == ${packet//[!0-9]/}
48+
49+
echo test access denied to mysql database
50+
rc=0
51+
sql 'select user, host from mysql.user' || rc=$?
52+
test "$rc" -gt 0
53+
54+
echo test wrong password is denied
55+
rc=0
56+
sql 'select user(), current_user(), version()' -p"wrongpassword" || rc=$?
57+
test "$rc" -gt 0
58+
)
59+
60+
service mariadb status || service mysql status
61+
62+
echo success

t/Makefile

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
2+
3+
test_container:
4+
( for f in *.sh; do ./$$f && continue; echo FAIL $$f; exit 1 ; done )
5+
6+
test_container_fast:
7+
( for f in *.sh; do T_CACHE_PACKAGES=1 ./$$f && continue; echo FAIL $$f; exit 1 ; done )
8+

t/README.md

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
Scripts to test SLS changes in podman containers
2+
-------------------
3+
4+
The goal is to cover following workflow:
5+
6+
* Change files related to an individual state.
7+
* Spawn a container with a local standalone salt node and apply the states.
8+
* Check basic bash commands to verify outcome.
9+
10+
The test is set of bash commands.
11+
The script relies on shebang to prepare an image and spawn a container with the sls files.
12+
It is also ready to test salt states using set of commands `salt-call --local`.
13+
14+
###### Example: Run test for mysql states:
15+
16+
```bash
17+
cd t
18+
./01-smoke-server.sh
19+
```
20+
21+
#### Challenge 1: By default, a container is destroyed when the test finishes.
22+
23+
This is to simplify re-run of tests and do not flood machine with leftover containers after tests.
24+
To make sure container stays around after faiure - set environment variable *T_PAUSE_ON_FAILURE* to 1
25+
26+
###### Example: Connect to the container after test failure
27+
28+
```bash
29+
> # terminal 1
30+
> echo fail >> 01-smoke-server.sh
31+
> T_PAUSE_ON_FAILURE=1 ./01-smoke-server.sh
32+
...
33+
bash: line 18: fail: command not found
34+
Test failed, press any key to finish
35+
```
36+
The terminal will wait for any input to finish the test and clean up the container.
37+
Now use another terminal window to check the running podman container and get into it for eventual troubleshooting:
38+
39+
```bash
40+
> # terminal 2
41+
> podman ps
42+
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
43+
2a37d23503fa localhost/mysql.formula.t38c8b1d778efa61c676f1aa99b2aded5.image:latest 4 minutes ago Up 4 minutes ago mysql.formula.t38c8b1d778efa61c676f1aa99b2aded5.01-smoke-server.sh
44+
> # use copy container id to start bash in it (hint: or bash completion should work for container name as well)
45+
> podman exec -it mysql.formuls.t38c8b1d778efa61c676f1aa99b2aded5.01-smoke-server.sh bash
46+
2a37d23503fa:/opt/project # ls
47+
bin encrypted_pillar_recipients ENCRYPTION.md FORMULAS.yaml gpgkeys pillar README.md salt t test
48+
2a37d23503fa:/opt/project # # now we are inside the container and can troubleshoot outcome of salt commands
49+
2a37d23503fa:/opt/project # rcmysql status
50+
* mariadb.service - MariaDB database server
51+
Loaded: loaded (/usr/lib/systemd/system/mariadb.service; disabled; vendor preset: disabled)
52+
Active: active (running) since Fri 2023-03-17 12:45:24 UTC; 10min ago
53+
```
54+
55+
#### Challenge 2: Vary OS in container.
56+
57+
Create new file Dockerfile.%osname% similar to existing Docker files in t/lib.
58+
Use environment variable T_IMAGE=%osname% to let scripts use corresponding Dockerfile.
59+
By default tests are run with t/Dockerfile.opensuse.leap
60+
61+
#### Challenge 3: Cache packages inside test image.
62+
63+
(Currently works only with default docker image, i.e. T_IMAGE is empty).
64+
Downloading and installing packages may be time consuming, so sometimes it may be advantageous to have an option to pre-install required packages inside image, in which the test will be run. (So the test will concentrate on verifying other aspects of salt states, without spending time on installing packages).
65+
At the same time the CI needs to verify salt states related to installation, so it must run the test without such caching.
66+
Such caching is implemented as optional parameters to shebang command in the test scripts. These parameters are ignored unless global variable *T_CACHE_PACKAGES* is set to 1.
67+
68+
```bash
69+
> # check parameter in shebang:
70+
> head -n 1 01-smoke-server.sh
71+
#!lib/test-in-container-systemd.sh mariadb
72+
> # run the test in a container with preinstalled mariadb package as specified above:
73+
> T_CACHE_PACKAGES=1 ./01-smoke-server.sh
74+
> # run the test in a container without preinstalled mariadb package (will take longer, but will verify package installation as part of test)
75+
> ./01-smoke-server.sh
76+
```
77+

t/lib/Dockerfile.debian.11

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM debian:11
2+
ENV container podman
3+
4+
ENV LANG en_US.UTF-8
5+
6+
# these are needed to run test
7+
RUN apt-get -y update && apt-get -y upgrade
8+
RUN apt-get -y install systemd salt-minion curl sudo
9+
10+
##DUMMY
11+
12+
RUN mkdir -p /srv/salt/ && \
13+
sed -i 's^\#*\s*file_client: .*$^file_client: local\nsystemd.scope: False\nenable_fqdns_grains: False^' /etc/salt/minion
14+
15+
ADD mysql /srv/salt/mysql
16+
17+
WORKDIR /opt/project
18+
19+
ENTRYPOINT ["/bin/systemd"]

t/lib/Dockerfile.opensuse.leap

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
FROM registry.opensuse.org/opensuse/leap
2+
ENV container podman
3+
4+
ENV LANG en_US.UTF-8
5+
6+
RUN test ! -f /var/log/zypper.log || mv /var/log/zypper.log /var/log/zypper.log.preinstalled
7+
8+
# these are needed to run test
9+
RUN zypper -vvvn install systemd salt-minion sudo
10+
11+
##DUMMY
12+
13+
RUN mkdir -p /srv/salt/ && \
14+
sed -i 's^\#*\s*file_client: .*$^file_client: local\nsystemd.scope: False\nenable_fqdns_grains: False^' /etc/salt/minion && \
15+
sed -i '/pam_systemd.so/d' /etc/pam.d/common-session-pc # delete pam_systemd , otherwise sudo will hang
16+
17+
ADD mysql /srv/salt/mysql
18+
19+
WORKDIR /opt/project
20+
21+
ENTRYPOINT ["/usr/lib/systemd/systemd"]

t/lib/test-in-container-systemd.sh

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
#!/bin/bash
2+
#
3+
# Copyright (C) 2023 SUSE LLC
4+
#
5+
# This program is free software; you can redistribute it and/or modify
6+
# it under the terms of the GNU General Public License as published by
7+
# the Free Software Foundation; either version 2 of the License, or
8+
# (at your option) any later version.
9+
#
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU General Public License for more details.
14+
#
15+
# You should have received a copy of the GNU General Public License along
16+
# with this program; if not, see <http://www.gnu.org/licenses/>.
17+
18+
last=${@:$#} # last parameter
19+
other=${*%${!#}} # all parameters except the last
20+
21+
testcase=$last
22+
23+
set -euo pipefail
24+
PODMAN=podman
25+
image=${T_IMAGE-opensuse.leap}
26+
(
27+
PODMAN_info="$($PODMAN info >/dev/null 2>&1)" || $PODMAN info
28+
[ -n "$testcase" ] || (echo No testcase provided; exit 1)
29+
[ -f "$testcase" ] || (echo Cannot find file "$testcase"; exit 1 )
30+
) >&2
31+
32+
thisdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
33+
basename=$(basename "$testcase")
34+
basename=${basename,,}
35+
basename=${basename//:/_}
36+
37+
othermd5=
38+
test -z "$other" || othermd5=($(echo "$other" | md5sum -))
39+
40+
ident=mysql.formula.t$othermd5
41+
containername="$ident.${basename,,}"
42+
43+
# we use variable T_CACHE_PACKAGES to speedup testing and make sure that
44+
(
45+
if test -z "$other" || \
46+
test "$T_IMAGE" != "" || \
47+
test "${T_CACHE_PACKAGES:-}" != 1
48+
then
49+
cat $thisdir/Dockerfile.${image}
50+
else
51+
ar=""
52+
in="zypper -vvvn in "
53+
for pkg in $other vim; do
54+
if [[ $pkg == *:* ]]; then
55+
n=${pkg//*:}
56+
ar="$ar zypper -n ar http://download.opensuse.org/repositories/$pkg/\\\\\$releasever/ $n;"
57+
in="$in $n"
58+
else
59+
in="$in $pkg"
60+
fi
61+
done
62+
test -z "$ar" || ar="$ar zypper --gpg-auto-import-keys ref; "
63+
64+
sed "s,\#\#DUMMY,RUN $ar $in,g" $thisdir/Dockerfile.${T_IMAGE}
65+
fi
66+
67+
) | cat | $PODMAN build -t $ident.image -f - $thisdir/../..
68+
69+
map_port=""
70+
[ -z "${EXPOSE_PORT:-}" ] || map_port="-p $EXPOSE_PORT:80"
71+
$PODMAN run --privileged --rm $map_port --name "$containername" -d -v"$thisdir/../..":/opt/project --add-host localhost:127.0.0.1 -- $ident.image
72+
73+
in_cleanup=0
74+
75+
ret=111
76+
77+
function cleanup {
78+
[ "$in_cleanup" != 1 ] || return
79+
in_cleanup=1
80+
if [ "$ret" != 0 ] && [ -n "${T_PAUSE_ON_FAILURE-}" ]; then
81+
read -rsn1 -p"Test failed, press any key to finish";echo
82+
fi
83+
[ "$ret" == 0 ] || echo FAIL $basename
84+
$PODMAN stop -t 0 "$containername" >&/dev/null || :
85+
}
86+
87+
trap cleanup INT TERM EXIT
88+
counter=1
89+
90+
# wait container start
91+
until [ $counter -gt 10 ]; do
92+
sleep 0.5
93+
$PODMAN exec "$containername" pwd >& /dev/null && break
94+
((counter++))
95+
done
96+
97+
$PODMAN exec "$containername" pwd >& /dev/null || (echo Cannot start container; exit 1 ) >&2
98+
99+
echo "$*"
100+
# [ -z $initscript ] || echo "bash -xe /opt/project/t/$initscript" | $PODMAN exec -i "$containername" bash -x
101+
102+
set +e
103+
$PODMAN exec -e TESTCASE="$testcase" -i "$containername" bash -xe < "$testcase"
104+
ret=$?
105+
( exit $ret )
106+

0 commit comments

Comments
 (0)