CI: add backwards compatibility checks
[tinc] / .ci / compat / run.sh
1 #!/bin/bash
2
3 # Three nodes are initialized:
4 #   latest : created from the latest commit that triggered this CI job
5 #   tinc11 : from the latest tag in tinc 1.1 branch
6 #   tinc10 : from the latest commit in tinc 1.0 branch
7 #
8 # The latter two are configured by using import/export/exchange.
9 # Since tinc 1.0 doesn't support that, host configs are copied to its hosts directory.
10 # Then nodes are connected and some light testing is performed to make sure they work together.
11
12 set -euo pipefail
13
14 nodes='latest tinc11 tinc10'
15 total_nodes=3
16
17 declare -A refs=(
18   [tinc10]='origin/master'
19   [tinc11]="$(git describe --abbrev=0 --match='release-*')"
20   [latest]='HEAD'
21 )
22
23 declare -A addr=(
24   [tinc10]='192.168.1.1'
25   [tinc11]='192.168.1.2'
26   [latest]='192.168.1.3'
27 )
28
29 src=/usr/local/src
30 etc=/usr/local/etc
31
32 mkdir -p $src $etc
33
34 archive() {
35   tar -caf /tmp/tests.tar.gz /usr/local/etc || true
36 }
37
38 header() {
39   echo >&2 '################################################################################'
40   echo >&2 "# $*"
41   echo >&2 '################################################################################'
42 }
43
44 build_meson() {
45   meson setup "$1" -D prefix="/opt/$1"
46   meson install -C "$1"
47 }
48
49 build_autotools() {
50   autoreconf -fsi
51   ./configure --prefix="/opt/$1"
52   make -j"$(nproc)"
53   make install
54 }
55
56 build() {
57   local ref="$1"
58   header "Building tinc (ref $ref)"
59
60   git clone "$PWD" "$src/$ref" -b "compat-$ref"
61   pushd "$src/$ref"
62
63   if [[ -f meson.build ]]; then
64     build_meson "$ref"
65   else
66     build_autotools "$ref"
67   fi
68
69   popd
70   mkdir -p "/opt/$ref/var/run"
71 }
72
73 wait_network() {
74   local from="$1"
75   local to="$2"
76   local total=0
77
78   while ! ip netns exec "$from" ping -W1 -c1 "${addr[$to]}" >/dev/null; do
79     total=$((total + 1))
80
81     if [[ total -gt 60 ]]; then
82       echo >&2 "Network connection between $from and $to is not working"
83       exit 1
84     fi
85
86     echo >&2 "Network isn't ready yet..."
87     sleep 1
88   done
89 }
90
91 test_network() {
92   local from="$1"
93   local to="$2"
94
95   wait_network "$from" "$to"
96
97   header "Sending data between $from and $to"
98
99   ip netns exec "$from" \
100     iperf3 --time 1 --client "${addr[$to]}"
101 }
102
103 test_sign_verify() {
104   local signer="$1"
105   local verifier="$2"
106   local output="$etc/$signer/signed"
107
108   header "Test signature verification between $signer and $verifier"
109
110   "$signer" sign >"$output" <<<"text message for node $signer to sign"
111
112   for peer in "$signer" '*'; do
113     "$verifier" verify "$peer" "$output"
114     "$verifier" verify "$peer" <"$output"
115   done
116 }
117
118 test_node_status() {
119   local node="$1"
120
121   header "Checking node status for $node"
122
123   reachable="$("$node" dump reachable nodes | wc -l)"
124   echo >&2 "Node $node can reach $reachable nodes"
125
126   [[ $reachable == "$total_nodes" ]]
127
128   for peer in $nodes; do
129     echo >&2 -n "$node info $peer: "
130     "$node" info "$peer" | tee /dev/stderr | grep -E -q '(can reach itself|directly)'
131   done
132 }
133
134 latest() {
135   /opt/latest/sbin/tinc -c $etc/latest "$@"
136 }
137
138 tinc11() {
139   /opt/tinc11/sbin/tinc -c $etc/tinc11 "$@"
140 }
141
142 header 'Creating branches'
143
144 for node in $nodes; do
145   echo >&2 "    $node: $(git rev-parse "compat-$node")"
146   git branch "compat-$node" "${refs[$node]}"
147 done
148
149 build tinc10
150 build tinc11
151 build latest
152
153 header 'Initializing node from the latest commit'
154
155 latest <<EOF
156   init latest
157   set Address localhost
158   set Port 30000
159   set Interface latest
160   set Subnet ${addr[latest]}
161   set Compression 0
162   set LogLevel 5
163 EOF
164
165 header 'Initializing node from the latest tag'
166
167 tinc11 <<EOF
168   init tinc11
169   set Address localhost
170   set Port 30001
171   set Interface tinc11
172   set Subnet ${addr[tinc11]}
173   set Compression 3
174   set LogLevel 5
175 EOF
176
177 header 'Initializing node for tinc 1.0'
178
179 mkdir -p $etc/tinc10/hosts
180
181 cat >$etc/tinc10/tinc.conf <<EOF
182 Name = tinc10
183 Interface = tinc10
184 Compression = 10
185 LogLevel = 5
186 EOF
187
188 cat >$etc/tinc10/hosts/tinc10 <<EOF
189 Address = localhost
190 Port = 30002
191 Subnet = ${addr[tinc10]}
192 EOF
193
194 /opt/tinc10/sbin/tincd -c $etc/tinc10 --generate-keys
195
196 trap archive EXIT INT TERM
197
198 header 'Creating network namespaces'
199
200 for ns in $nodes; do
201   ip netns add "$ns"
202 done
203
204 header 'Creating network configuration scripts'
205
206 for node in $nodes; do
207   tinc_up="$etc/$node/tinc-up"
208
209   cat >"$tinc_up" <<EOF
210 #!/bin/bash
211 set -eu
212 ip link set dev $node netns $node
213 ip netns exec $node ip addr add ${addr[$node]}/24 dev $node
214 ip netns exec $node ip link set $node up
215 ip netns exec $node ip link set lo up
216 ip netns exec $node iperf3 --server --daemon
217 EOF
218
219   chmod 755 "$tinc_up"
220 done
221
222 header 'Exchanging host files'
223
224 # Not all configs are copied to make sure 'peer exchange' is working
225 # tinc10 <--> latest <--> tinc11
226 latest export | tinc11 exchange | latest import
227 cp $etc/tinc10/hosts/tinc10 $etc/latest/hosts/
228 cp $etc/latest/hosts/latest $etc/tinc10/hosts/
229
230 header "Starting nodes"
231
232 for node in $nodes; do
233   tincd="/opt/$node/sbin/tincd"
234   echo >&2 "Starting node $node ($tincd)"
235
236   "$tincd" --version
237
238   "$tincd" \
239     --config "$etc/$node" \
240     --pidfile "$etc/$node/pid" \
241     --logfile "$etc/$node/log" \
242     --debug 5
243 done
244
245 header 'Running connectivity tests'
246
247 for client in $nodes; do
248   for server in $nodes; do
249     if [[ $client != "$server" ]]; then
250       test_network "$client" "$server"
251     fi
252   done
253 done
254
255 test_node_status latest
256 test_node_status tinc11
257
258 test_sign_verify latest tinc11
259 test_sign_verify tinc11 latest