Skip to content

Commit ac64e14

Browse files
[WIP] Adding docker-compose as a foundation for functional tests
1 parent d542651 commit ac64e14

6 files changed

Lines changed: 302 additions & 13 deletions

File tree

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,3 +9,4 @@ dist/
99
testdata
1010

1111
vendor/
12+
.idea/

Dockerfile

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,25 +32,16 @@ RUN chown nobody:nobody bin/e2d
3232

3333
############################
3434
# Final stage: Just the executable and bare minimum other files
35-
FROM scratch AS final
35+
FROM alpine:3.14.2 AS final
3636

37-
LABEL MAINTAINER="Critical Stack <dev@criticalstack.com>"
38-
39-
# Import the user and group files from the first stage.
40-
COPY --from=go-builder /user/group /user/passwd /etc/
41-
42-
# Import the Certificate-Authority certificates for enabling HTTPS.
43-
COPY --from=go-builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
44-
45-
# Perform any further action as an unprivileged user.
46-
USER nobody:nobody
37+
LABEL MAINTAINER="NXTLytics <dev@nxtlytics.com>"
4738

4839
# e2d runs on port 2379,2380,7980
4940
EXPOSE 2379
5041
EXPOSE 2380
5142
EXPOSE 7980
5243

5344
# Add e2d bin
54-
COPY --from=go-builder --chown=nobody:nobody /e2d/bin/e2d /
45+
COPY --from=go-builder /e2d/bin/e2d /
5546

56-
ENTRYPOINT ["/e2d"]
47+
ENTRYPOINT ["/e2d"]

tests/Dockerfile

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
FROM amazonlinux:2.0.20210813.1-with-sources
2+
3+
COPY test.sh /usr/local/bin/test.sh
4+
5+
RUN chmod +x /usr/local/bin/test.sh && \
6+
/usr/local/bin/test.sh -p container

tests/README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
## How to run tests?
2+
3+
```shell
4+
$ cd ${GOPATH}/github.com/criticalstack/e2d/tests/
5+
$ docker-compose build
6+
$ docker-compose up
7+
```

tests/docker-compose.yml

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
version: "3.9"
2+
services:
3+
builder:
4+
build:
5+
context: ../
6+
dockerfile: Dockerfile
7+
volumes:
8+
- e2d:/mnt
9+
- ./test.sh:/usr/local/bin/test.sh:ro
10+
entrypoint: sh
11+
command: -c 'mkdir -p /mnt/bin && cp /e2d /mnt/bin/e2d'
12+
e2d0:
13+
build:
14+
context: .
15+
dockerfile: Dockerfile
16+
image: e2d-tester:local
17+
hostname: e2d0
18+
depends_on:
19+
- builder
20+
volumes:
21+
- e2d:/mnt
22+
entrypoint: bash
23+
command: test.sh -p member
24+
e2d1:
25+
depends_on:
26+
- e2d0
27+
image: e2d-tester:local
28+
hostname: e2d1
29+
volumes:
30+
- e2d:/mnt
31+
entrypoint: bash
32+
command: test.sh -p member
33+
links:
34+
- e2d0
35+
- e2d2
36+
e2d2:
37+
depends_on:
38+
- e2d0
39+
image: e2d-tester:local
40+
hostname: e2d2
41+
volumes:
42+
- e2d:/mnt
43+
entrypoint: bash
44+
command: test.sh -p member
45+
links:
46+
- e2d0
47+
tester:
48+
depends_on:
49+
- e2d0
50+
- e2d1
51+
- e2d2
52+
image: e2d-tester:local
53+
hostname: tester
54+
volumes:
55+
- e2d:/mnt
56+
entrypoint: bash
57+
command: test.sh -p tester
58+
links:
59+
- e2d0
60+
- e2d1
61+
- e2d2
62+
volumes:
63+
e2d:
64+
networks:
65+
default:
66+
name: e2d
67+
driver: bridge

tests/test.sh

Lines changed: 217 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,217 @@
1+
#!/usr/bin/env bash
2+
set -euo pipefail
3+
IFS=$'\n\t'
4+
5+
# Constants
6+
THIS_SCRIPT=$(basename $0)
7+
PADDING=$(printf %-${#THIS_SCRIPT}s " ")
8+
SHARED_VOLUME_PATH='/mnt'
9+
E2D_DIR="${SHARED_VOLUME_PATH}/bin"
10+
E2D_BIN="${E2D_DIR}/e2d"
11+
CA_DIR="${SHARED_VOLUME_PATH}/ca"
12+
CA_KEY="${CA_DIR}/ca.key"
13+
CA_CRT="${CA_DIR}/ca.crt"
14+
CLIENT_CRT='./client.crt'
15+
CLIENT_KEY='./client.key'
16+
PEER_CRT='./peer.crt'
17+
PEER_KEY='./peer.key'
18+
SERVER_CRT='./server.crt'
19+
SERVER_KEY='./server.key'
20+
SNAP_DIR="${SHARED_VOLUME_PATH}/snapshots/"
21+
E2D_VAR_DIR='/var/lib/etcd'
22+
E2D_DATA_DIR="${E2D_VAR_DIR}/data"
23+
E2D_MEMBER0='e2d0'
24+
E2D_MEMBER1='e2d1'
25+
E2D_MEMBER2='e2d2'
26+
CURRENT_USER="$(whoami)"
27+
TEST_USERNAME='k8s'
28+
ETCD_VERSION='v3.5.0'
29+
ETCDCTL_BIN="/usr/local/bin/etcdctl"
30+
OS="$(uname | tr '[:upper:]' '[:lower:]')"
31+
case "$(uname -m)" in
32+
x86_64)
33+
ARCH='amd64'
34+
;;
35+
aarch64|arm64)
36+
ARCH='arm64'
37+
;;
38+
*)
39+
echo 'Arch $(uname -m) nor supported'
40+
exit 1
41+
;;
42+
esac
43+
44+
function usage() {
45+
echo "Usage:"
46+
echo "${THIS_SCRIPT} -p <Container profile, e.g. builder, leader, member, tester, container>"
47+
echo
48+
echo "Configures containers inside docker-compose to test e2d"
49+
exit 1
50+
}
51+
52+
function create_test_user() {
53+
echo "Creating user and group ${TEST_USERNAME}"
54+
groupadd -r -g 1000 ${TEST_USERNAME}
55+
useradd -r -g ${TEST_USERNAME} -u 1000 ${TEST_USERNAME}
56+
}
57+
58+
function install_base_rpms() {
59+
echo 'installing amazon linux 2 base RPMs for testing e2d'
60+
yum install -y \
61+
file \
62+
iproute \
63+
iputils \
64+
yum-utils \
65+
vim \
66+
telnet \
67+
procps \
68+
tar \
69+
tree
70+
}
71+
72+
function install_etcdctl() {
73+
local ETCD_TAR='etcd.tar.gz'
74+
curl -sL "https://github.com/etcd-io/etcd/releases/download/${ETCD_VERSION}/etcd-${ETCD_VERSION}-${OS}-${ARCH}.tar.gz" -o "${ETCD_TAR}"
75+
tar -xvzf "${ETCD_TAR}"
76+
mv "etcd-${ETCD_VERSION}-${OS}-${ARCH}/etcdctl" "${ETCDCTL_BIN}"
77+
rm -rf "${ETCD_TAR}" "etcd-${ETCD_VERSION}-${OS}-${ARCH}/"
78+
chmod +x "${ETCDCTL_BIN}"
79+
}
80+
81+
function create_var_etcd_dir() {
82+
mkdir -p "${E2D_VAR_DIR}"
83+
chown -R ${TEST_USERNAME}: "${E2D_VAR_DIR}"
84+
}
85+
86+
function container_setup() {
87+
install_base_rpms
88+
create_test_user
89+
create_var_etcd_dir
90+
install_etcdctl
91+
}
92+
93+
function is_e2d_ready() {
94+
until [[ -x "${E2D_BIN}" ]]; do
95+
echo "${E2D_BIN} is not executable by ${CURRENT_USER}, yet"
96+
sleep 2
97+
done
98+
echo "${E2D_BIN} is executable by ${CURRENT_USER}"
99+
}
100+
101+
function create_etcd_ca() {
102+
is_e2d_ready
103+
mkdir -p "${CA_DIR}" "${SNAP_DIR}"
104+
"${E2D_BIN}" pki init --ca-key "${CA_KEY}" --ca-cert "${CA_CRT}"
105+
chown -R ${TEST_USERNAME}: "${SHARED_VOLUME_PATH}/"
106+
}
107+
108+
function is_ca_ready() {
109+
until su ${TEST_USERNAME} -c "test -O ${CA_KEY}" && su ${TEST_USERNAME} -c "test -O ${CA_CRT}"; do
110+
echo "${CA_KEY} and/or ${CA_CRT} are not owned by ${TEST_USERNAME}, yet"
111+
echo "contents of ${SHARED_VOLUME_PATH} are"
112+
tree "${SHARED_VOLUME_PATH}"
113+
stat "${CA_KEY}" "${CA_CRT}" || true
114+
sleep 2
115+
done
116+
echo "${CA_KEY} and ${CA_CRT} are owned by ${TEST_USERNAME}"
117+
}
118+
119+
function get_e2d_name() {
120+
echo "${E2D_NAME:-$(cat /etc/hostname)}"
121+
}
122+
123+
function generate_certs() {
124+
is_ca_ready
125+
${E2D_BIN} pki gencerts --hosts "$(get_e2d_name)" --ca-cert "${CA_CRT}" --ca-key "${CA_KEY}"
126+
chown ${TEST_USERNAME}: *.{key,crt}
127+
echo "certs were generated"
128+
}
129+
130+
function get_bootstrap_addrs() {
131+
case "$(get_e2d_name)" in
132+
e2d0)
133+
echo "$(get_e2d_name):7980,${E2D_MEMBER1}:7980,${E2D_MEMBER2}:7980"
134+
;;
135+
e2d1)
136+
echo "$(get_e2d_name):7980,${E2D_MEMBER0}:7980,${E2D_MEMBER2}:7980"
137+
;;
138+
e2d2)
139+
echo "$(get_e2d_name):7980,${E2D_MEMBER0}:7980,${E2D_MEMBER1}:7980"
140+
;;
141+
esac
142+
}
143+
144+
function run_e2d() {
145+
if [[ "$(get_e2d_name)" == 'e2d0' ]]; then
146+
create_etcd_ca
147+
fi
148+
generate_certs
149+
su ${TEST_USERNAME} -c "${E2D_BIN} run -n 3 --snapshot-url file://${SNAP_DIR} \
150+
--name=$(get_e2d_name) \
151+
--data-dir=${E2D_DATA_DIR} \
152+
--ca-cert=${CA_CRT} \
153+
--ca-key=${CA_KEY} \
154+
--peer-cert=${PEER_CRT} \
155+
--peer-key=${PEER_KEY} \
156+
--server-cert=${SERVER_CRT} \
157+
--server-key=${SERVER_KEY} \
158+
--bootstrap-addrs $(get_bootstrap_addrs)"
159+
}
160+
161+
function is_leader_up() {
162+
until curl --cert "${CLIENT_CRT}" --key "${CLIENT_KEY}" -m 1 -k "https://${E2D_MEMBER0}:2379"; do
163+
echo "${E2D_MEMBER0} is not up yet"
164+
sleep 5
165+
done
166+
echo "${E2D_MEMBER0} is up and ready"
167+
}
168+
169+
function client_setup() {
170+
export ETCDCTL_CACERT="${CA_CRT}"
171+
export ETCDCTL_CERT="${CLIENT_CRT}"
172+
export ETCDCTL_KEY="${CLIENT_KEY}"
173+
export ETCDCTL_ENDPOINTS="https://${E2D_MEMBER0}:2379,https://${E2D_MEMBER1}:2379,https://${E2D_MEMBER2}:2379"
174+
}
175+
176+
function tests() {
177+
generate_certs
178+
client_setup
179+
is_leader_up
180+
etcdctl member list -w table
181+
etcdctl endpoint health -w table
182+
etcdctl endpoint status -w table
183+
sleep infinity
184+
}
185+
186+
while getopts ":p:" opt; do
187+
case ${opt} in
188+
p)
189+
PROFILE=${OPTARG} ;;
190+
\?)
191+
usage ;;
192+
:)
193+
usage ;;
194+
esac
195+
done
196+
197+
if [[ -z ${PROFILE:-""} ]] ; then
198+
usage
199+
fi
200+
201+
case "${PROFILE}" in
202+
container)
203+
container_setup
204+
;;
205+
member)
206+
run_e2d
207+
;;
208+
tester)
209+
tests
210+
;;
211+
client_setup)
212+
client_setup
213+
;;
214+
*)
215+
usage
216+
;;
217+
esac

0 commit comments

Comments
 (0)