Add smoke/basic functional test

Without this patch, we don't test on release whether kured actually
works and behave well.

This is a problem, as a functional issue could have been hidden by
a recent change, as our testing is minimalist (only test the
usability, not the functionality).
Instead of testing manually, we should ensure this in CI.

This fixes it by adding a github action which tests the previously
built artifacts before publishing a release. The job consume the helm
chart in our code tree  (note: this relies on the last released image),
and run a functional test triggering a coordinated restart of a
whole 5 node cluster deployed with kind, through github actions.

Note: The github action needs to reset docker configuration, else
the reboot of the node (a docker container in kind) will fail.
It will be correctly triggered, but the node will not come back up,
with its systemd log mentioning: "Failed to attach 1 to compat systemd cgroup".
This commit is contained in:
Jean-Philippe Evrard
2020-08-28 09:25:44 +02:00
parent b024898ed6
commit 3d75f1b37a
4 changed files with 162 additions and 0 deletions
+8
View File
@@ -0,0 +1,8 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: control-plane
- role: control-plane
- role: worker
- role: worker
+66
View File
@@ -0,0 +1,66 @@
# This needs all the previous artifacts to be created:
# the image should be published, the repo should be tagged, the helm
# chart pushed. It's assumed everything is working, and we are doing
# a last final test at the release creation time to _ensure_ we can
# release. At this point it's still time to back off in case of problem,
# not publish the release and iterate on tags.
name: Smoke test
on:
push:
branches:
- '**'
release:
types: created
jobs:
deploy-manifests:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: "0"
- name: Workaround "Failed to attach 1 to compat systemd cgroup /actions_job/..." on gh actions
run: |
sudo bash << EOF
cp /etc/docker/daemon.json /etc/docker/daemon.json.old
echo '{}' > /etc/docker/daemon.json
systemctl restart docker || journalctl --no-pager -n 500
systemctl status docker
EOF
- name: Create 5 node kind cluster
uses: helm/kind-action@master
with:
config: .github/kind-cluster.yaml
- name: Deploy kured on default namespace with its helm chart
run: |
curl -o helm3.tgz https://get.helm.sh/helm-v3.3.0-linux-amd64.tar.gz
tar xf helm3.tgz
./linux-amd64/helm install kured ./charts/kured/ --set configuration.period=1m
kubectl config set-context kind-chart-testing
kubectl get ds --all-namespaces
kubectl describe ds kured
- name: Ensure kured is ready
uses: nick-invision/retry@v1
with:
timeout_minutes: 10
max_attempts: 10
retry_wait_seconds: 60
# DESIRED CURRENT READY UP-TO-DATE AVAILABLE should all be = 5
command: "kubectl get ds kured | grep -E 'kured.*5.*5.*5.*5.*5' "
- name: Create reboot sentinel files
run: |
./tests/kind/create-reboot-sentinels.sh
- name: Follow reboot until success
env:
DEBUG: true
run: |
./tests/kind/follow-coordinated-reboot.sh
+12
View File
@@ -0,0 +1,12 @@
#!/usr/bin/env bash
# USE KUBECTL_CMD to pass context and/or namespaces.
KUBECTL_CMD="${KUBECTL_CMD:-kubectl}"
SENTINEL_FILE="${SENTINEL_FILE:-/var/run/reboot-required}"
echo "Creating reboot sentinel on all nodes"
for nodename in $("$KUBECTL_CMD" get nodes -o name); do
docker exec "${nodename/node\//}" hostname
docker exec "${nodename/node\//}" touch "${SENTINEL_FILE}"
done
+76
View File
@@ -0,0 +1,76 @@
#!/usr/bin/env bash
NODECOUNT=${NODECOUNT:-5}
KUBECTL_CMD="${KUBECTL_CMD:-kubectl}"
DEBUG="${DEBUG:-false}"
tmp_dir=$(mktemp -d -t kured-XXXX)
declare -A was_unschedulable
declare -A has_recovered
max_attempts="60"
sleep_time=60
attempt_num=1
set +o errexit
echo "There are $NODECOUNT nodes in the cluster"
until [ ${#was_unschedulable[@]} == "$NODECOUNT" ] && [ ${#has_recovered[@]} == "$NODECOUNT" ]
do
echo "${#was_unschedulable[@]} nodes were removed from pool once:" "${!was_unschedulable[@]}"
echo "${#has_recovered[@]} nodes removed from the pool are now back:" "${!has_recovered[@]}"
"$KUBECTL_CMD" get nodes -o custom-columns=NAME:.metadata.name,SCHEDULABLE:.spec.unschedulable --no-headers > "$tmp_dir"/node_output
if [[ "$DEBUG" == "true" ]]; then
# This is useful to see if a node gets stuck after drain, and doesn't
# come back up.
echo "Result of command $KUBECTL_CMD get nodes ... showing unschedulable nodes:"
cat "$tmp_dir"/node_output
fi
while read -r node; do
unschedulable=$(echo "$node" | grep true | cut -f 1 -d ' ')
if [ -n "$unschedulable" ] && [ -z ${was_unschedulable["$unschedulable"]+x} ] ; then
echo "$unschedulable is now unschedulable!"
was_unschedulable["$unschedulable"]=1
fi
schedulable=$(echo "$node" | grep '<none>' | cut -f 1 -d ' ')
if [ -n "$schedulable" ] && [ ${was_unschedulable["$schedulable"]+x} ] && [ -z ${has_recovered["$schedulable"]+x} ]; then
echo "$schedulable has recovered!"
has_recovered["$schedulable"]=1
fi
done < "$tmp_dir"/node_output
if [[ "${#has_recovered[@]}" == "$NODECOUNT" ]]; then
echo "All nodes recovered."
break
else
if (( attempt_num == max_attempts ))
then
echo "Attempt $attempt_num failed and there are no more attempts left!"
exit 1
else
echo "Attempt $attempt_num failed! Trying again in $sleep_time seconds..."
sleep "$sleep_time"
fi
fi
(( attempt_num++ ))
done
if [[ "$DEBUG" == "true" ]]; then
# This is useful to see if containers have crashed
echo "Debug logs"
echo "docker ps:"
docker ps
# This is useful to see if the nodes have _properly_ rebooted.
# It should show the reboot/two container starts per node.
for name in chart-testing-control-plane chart-testing-control-plane2 chart-testing-control-plane3 chart-testing-worker chart-testing-worker2; do
echo "############################################################"
echo "docker logs for node $name:"
docker logs $name
done
fi
set -o errexit
echo "Test successful"
rm "$tmp_dir"/node_output
rmdir "$tmp_dir"