2021-05-20 08:38:11 +00:00
#!/usr/bin/env bash
2021-07-05 11:07:37 +00:00
KUBECONFIG = "kind.yaml"
2021-05-20 08:38:11 +00:00
KIND_CLUSTER = "kind-cluster-kilo"
KIND_BINARY = " ${ KIND_BINARY :- kind } "
KUBECTL_BINARY = " ${ KUBECTL_BINARY :- kubectl } "
2021-06-15 18:38:21 +00:00
KGCTL_BINARY = " ${ KGCTL_BINARY :- kgctl } "
2021-05-20 08:38:11 +00:00
KILO_IMAGE = " ${ KILO_IMAGE :- squat /kilo } "
2021-06-15 10:54:27 +00:00
retry( ) {
local COUNT = " ${ 1 :- 10 } "
local SLEEP = " ${ 2 :- 5 } "
local ERROR = $3
[ -n " $ERROR " ] && ERROR = " $ERROR "
shift 3
for c in $( seq 1 " $COUNT " ) ; do
if " $@ " ; then
2021-06-15 18:38:21 +00:00
return 0
2021-06-15 10:54:27 +00:00
else
2021-07-05 20:09:43 +00:00
printf "%s(attempt %d/%d)\n" " $ERROR " " $c " " $COUNT " | color " $YELLOW " 1>& 2
2021-06-15 10:54:27 +00:00
if [ " $c " != " $COUNT " ] ; then
2021-07-05 20:09:43 +00:00
printf "retrying in %d seconds...\n" " $SLEEP " | color " $YELLOW " 1>& 2
2021-06-15 18:38:21 +00:00
sleep " $SLEEP "
2021-06-15 10:54:27 +00:00
fi
fi
done
return 1
}
2021-06-16 10:50:52 +00:00
_not( ) {
if " $@ " ; then
return 1
fi
return 0
}
2021-07-05 11:07:37 +00:00
# _kubectl is a helper that calls kubectl with the --kubeconfig flag.
_kubectl( ) {
$KUBECTL_BINARY --kubeconfig= " $KUBECONFIG " " $@ "
}
# _kgctl is a helper that calls kgctl with the --kubeconfig flag.
_kgctl( ) {
$KGCTL_BINARY --kubeconfig= " $KUBECONFIG " " $@ "
}
# _kind is a helper that calls kind with the --kubeconfig flag.
_kind( ) {
$KIND_BINARY --kubeconfig= " $KUBECONFIG " " $@ "
}
2021-07-05 11:14:23 +00:00
# shellcheck disable=SC2120
build_kind_config( ) {
local WORKER_COUNT = " ${ 1 :- 0 } "
export API_SERVER_PORT = " ${ 2 :- 6443 } "
export POD_SUBNET = " ${ 3 :- 10 .42.0.0/16 } "
export SERVICE_SUBNET = " ${ 4 :- 10 .43.0.0/16 } "
export WORKERS = ""
local i = 0
while [ " $i " -lt " $WORKER_COUNT " ] ; do
WORKERS = " $( printf "%s\n- role: worker" " $WORKERS " ) "
( ( i++) )
done
envsubst < ./kind-config.yaml
unset API_SERVER_PORT POD_SUBNET SERVICE_SUBNET WORKERS
}
2021-06-15 18:38:21 +00:00
create_interface( ) {
docker run -d --name= " $1 " --rm --network= host --cap-add= NET_ADMIN --device= /dev/net/tun -v /var/run/wireguard:/var/run/wireguard -e WG_LOG_LEVEL = debug leonnicolas/boringtun --foreground --disable-drop-privileges true " $1 "
}
delete_interface( ) {
docker rm --force " $1 "
}
create_peer( ) {
2021-07-05 11:07:37 +00:00
cat <<EOF | _kubectl apply -f -
2021-06-15 18:38:21 +00:00
apiVersion: kilo.squat.ai/v1alpha1
kind: Peer
metadata:
name: $1
spec:
allowedIPs:
- $2
persistentKeepalive: $3
publicKey: $4
EOF
}
delete_peer( ) {
2021-07-05 11:07:37 +00:00
_kubectl delete peer " $1 "
2021-06-15 18:38:21 +00:00
}
2021-05-20 08:38:11 +00:00
is_ready( ) {
2021-07-05 11:07:37 +00:00
for pod in $( _kubectl -n " $1 " get pods -o name -l " $2 " ) ; do
if ! _kubectl -n " $1 " get " $pod " | tail -n 1 | grep -q Running; then
2021-05-20 08:38:11 +00:00
return 1;
fi
done
return 0
}
# Returns non zero if one pod of the given name in the given namespace is not ready.
block_until_ready_by_name( ) {
2021-05-20 21:36:14 +00:00
block_until_ready " $1 " " app.kubernetes.io/name= $2 "
2021-05-20 08:38:11 +00:00
}
# Blocks until all pods of a deployment are ready.
block_until_ready( ) {
2021-06-15 10:54:27 +00:00
retry 30 5 " some $2 pods are not ready yet " is_ready " $1 " " $2 "
2021-05-20 08:38:11 +00:00
}
2021-06-17 09:48:35 +00:00
# create_cluster launches a kind cluster and deploys Kilo, Adjacency, and a helper with curl.
create_cluster( ) {
2021-07-05 11:14:23 +00:00
# shellcheck disable=SC2119
local CONFIG = " ${ 1 :- $( build_kind_config) } "
2021-07-05 11:07:37 +00:00
_kind delete clusters $KIND_CLUSTER > /dev/null
2021-05-20 08:38:11 +00:00
# Create the kind cluster.
2021-07-05 11:14:23 +00:00
_kind create cluster --name $KIND_CLUSTER --config <( echo " $CONFIG " )
2021-05-20 08:38:11 +00:00
# Load the Kilo image into kind.
2021-05-20 21:36:14 +00:00
docker tag " $KILO_IMAGE " squat/kilo:test
2021-07-05 11:07:37 +00:00
# This command does not accept the --kubeconfig flag, so call the command directly.
2021-05-20 08:38:11 +00:00
$KIND_BINARY load docker-image squat/kilo:test --name $KIND_CLUSTER
2021-06-15 18:38:21 +00:00
# Create the kubeconfig secret.
2021-07-05 11:07:37 +00:00
_kubectl create secret generic kubeconfig --from-file= kubeconfig = " $KUBECONFIG " -n kube-system
2021-05-20 08:38:11 +00:00
# Apply Kilo the the cluster.
2021-07-05 11:07:37 +00:00
_kubectl apply -f ../manifests/crds.yaml
_kubectl apply -f kilo-kind-userspace.yaml
2021-05-20 08:38:11 +00:00
block_until_ready_by_name kube-system kilo-userspace
2021-07-05 11:07:37 +00:00
_kubectl wait nodes --all --for= condition = Ready
2021-06-16 10:50:52 +00:00
# Wait for CoreDNS.
2021-05-20 08:38:11 +00:00
block_until_ready kube_system k8s-app= kube-dns
2021-06-17 09:48:35 +00:00
# Ensure the curl helper is not scheduled on a control-plane node.
2021-07-05 11:07:37 +00:00
_kubectl apply -f helper-curl.yaml
2021-06-16 10:50:52 +00:00
block_until_ready_by_name default curl
2021-07-05 11:07:37 +00:00
_kubectl taint node $KIND_CLUSTER -control-plane node-role.kubernetes.io/master:NoSchedule-
2021-07-13 11:05:19 +00:00
_kubectl apply -f https://raw.githubusercontent.com/kilo-io/adjacency/main/example.yaml
2021-08-18 20:51:51 +00:00
block_until_ready_by_name default adjacency
2021-06-16 10:50:52 +00:00
}
2021-06-17 09:48:35 +00:00
delete_cluster ( ) {
2021-07-05 11:07:37 +00:00
_kind delete clusters $KIND_CLUSTER
2021-06-17 09:48:35 +00:00
}
2021-06-16 10:50:52 +00:00
curl_pod( ) {
2021-07-05 17:40:39 +00:00
_kubectl get pods -l app.kubernetes.io/name= curl -o name | xargs -I{ } " $KUBECTL_BINARY " --kubeconfig= " $KUBECONFIG " exec { } -- /usr/bin/curl " $@ "
2021-05-20 08:38:11 +00:00
}
2021-06-15 10:54:27 +00:00
check_ping( ) {
2021-06-15 18:38:21 +00:00
local LOCAL
while [ $# -gt 0 ] ; do
case $1 in
--local)
LOCAL = true
; ;
esac
shift
done
2021-07-05 11:07:37 +00:00
for ip in $( _kubectl get pods -l app.kubernetes.io/name= adjacency -o jsonpath = '{.items[*].status.podIP}' ) ; do
2021-06-15 18:38:21 +00:00
if [ -n " $LOCAL " ] ; then
ping = $( curl -m 1 -s http://" $ip " :8080/ping)
else
2021-06-16 10:50:52 +00:00
ping = $( curl_pod -m 1 -s http://" $ip " :8080/ping)
2021-06-15 18:38:21 +00:00
fi
if [ " $ping " = "pong" ] ; then
echo " successfully pinged $ip "
else
printf 'failed to ping %s; expected "pong" but got "%s"\n' " $ip " " $ping "
return 1
fi
done
return 0
2021-05-20 08:38:11 +00:00
}
check_adjacent( ) {
2021-07-05 17:40:39 +00:00
curl_pod adjacency:8080/?format= fancy
2021-07-05 11:09:51 +00:00
[ " $( curl_pod -m 1 -s adjacency:8080/?format= json | jq '.[].latencies[].ok' | grep -c true ) " -eq $(( $1 * $1 )) ]
2021-05-20 08:38:11 +00:00
}
2021-06-15 18:38:21 +00:00
check_peer( ) {
local INTERFACE = $1
local PEER = $2
local ALLOWED_IP = $3
local GRANULARITY = $4
create_interface " $INTERFACE "
docker run --rm --entrypoint= /usr/bin/wg " $KILO_IMAGE " genkey > " $INTERFACE "
2021-06-16 08:37:17 +00:00
assert " create_peer $PEER $ALLOWED_IP 10 $( docker run --rm --entrypoint= /bin/sh -v " $PWD / $INTERFACE " :/key " $KILO_IMAGE " -c 'cat /key | wg pubkey' ) " "should be able to create Peer"
2021-07-05 11:07:37 +00:00
assert " _kgctl showconf peer $PEER --mesh-granularity= $GRANULARITY > $PEER .ini " "should be able to get Peer configuration"
2021-06-16 08:37:17 +00:00
assert " docker run --rm --network=host --cap-add=NET_ADMIN --entrypoint=/usr/bin/wg -v /var/run/wireguard:/var/run/wireguard -v $PWD / $PEER .ini:/peer.ini $KILO_IMAGE setconf $INTERFACE /peer.ini " "should be able to apply configuration from kgctl"
2021-06-15 18:38:21 +00:00
docker run --rm --network= host --cap-add= NET_ADMIN --entrypoint= /usr/bin/wg -v /var/run/wireguard:/var/run/wireguard -v " $PWD / $INTERFACE " :/key " $KILO_IMAGE " set " $INTERFACE " private-key /key
docker run --rm --network= host --cap-add= NET_ADMIN --entrypoint= /sbin/ip " $KILO_IMAGE " address add " $ALLOWED_IP " dev " $INTERFACE "
docker run --rm --network= host --cap-add= NET_ADMIN --entrypoint= /sbin/ip " $KILO_IMAGE " link set " $INTERFACE " up
docker run --rm --network= host --cap-add= NET_ADMIN --entrypoint= /sbin/ip " $KILO_IMAGE " route add 10.42/16 dev " $INTERFACE "
2021-06-16 08:37:17 +00:00
assert "retry 10 5 '' check_ping --local" "should be able to ping Pods from host"
2021-07-05 11:07:37 +00:00
assert_equals " $( _kgctl showconf peer " $PEER " ) " " $( _kgctl showconf peer " $PEER " --mesh-granularity= " $GRANULARITY " ) " "kgctl should be able to auto detect the mesh granularity"
2021-06-15 18:38:21 +00:00
rm " $INTERFACE " " $PEER " .ini
delete_peer " $PEER "
delete_interface " $INTERFACE "
}