Page MenuHomePhorge

No OneTemporary

Authored By
Unknown
Size
33 KB
Referenced Files
None
Subscribers
None
diff --git a/kolabctl b/kolabctl
index 072a110..0809052 100755
--- a/kolabctl
+++ b/kolabctl
@@ -1,961 +1,981 @@
#!/bin/bash
# shellcheck disable=SC2068
# shellcheck disable=SC2086
# shellcheck disable=SC2001
# shellcheck disable=SC2002
# shellcheck disable=SC2219
# shellcheck disable=SC2059
HOST=${HOST:-kolab.local}
NAMESPACE=${NAMESPACE:-kolab}
CHART_VERSION=${CHART_VERSION:-"4.0.6"}
CHART_URL=${CHART_URL:-"oci://quay.io/apheleiait/kolab/kolab"}
USERNAME=${USERNAME:-"apheleiait+kolab"}
PASSWORD=${PASSWORD:-"Z8Q8KT04M4ADF7D18PDINUG4V3ZO6GYP4JPPAUGPANO4KWGYS93LR7QQ5DGLFRQP"}
IMAGE_REGISTRY=${IMAGE_REGISTRY:-"quay.io/apheleiait/kolab"}
IMAGE_VERSION=${IMAGE_VERSION:-"4.0.6"}
export KUBECONFIG=${KUBECONFIG:-"$HOME/.kube/config"}
-[ -f kubeconfig.yaml ] && echo "Found a local kubeconfig.yaml" && export KUBECONFIG="kubeconfig.yaml"
+[ -f kubeconfig.yaml ] && export KUBECONFIG="kubeconfig.yaml"
### ========== Implementation Details ============
#Ensure we are connected to the correct cluster (localhost only for now)
__ensure_server() {
# We assume that if the namespace is kolab it's a k3s setup.
if [[ "$NAMESPACE" == "kolab" ]]; then
# Do we have any means to check if this makes sense?
echo
else
if [[ "$(oc project -q)" != "$NAMESPACE" ]]; then
echo "Wrong project on the server, or not openshift"
exit 1
fi
fi
}
__helm_upgrade() {
set -e
if [[ -f values.yaml ]]; then
ARGS="-f values.yaml"
fi
time helm upgrade -i kolab --create-namespace $ARGS $@ --namespace "$NAMESPACE" "$CHART_URL" --version "$CHART_VERSION"
command kubectl -n $NAMESPACE rollout status deployment
command helm status kolab -n $NAMESPACE
}
__helm_template() {
if [[ -f values.yaml ]]; then
ARGS="-f values.yaml"
fi
command helm template kolab --namespace "$NAMESPACE" "$CHART_URL" $ARGS $@ --version "$CHART_VERSION"
}
+
+kolab__apply() {
+ __helm_template > inflated.yaml
+ cat <<EOF > kustomization.yaml
+resources:
+ - inflated.yaml
+EOF
+ if [[ "$2" =~ "--force" ]]; then
+ command kubectl apply -k ./
+
+ else
+ command kubectl diff -k ./
+ read -p "Does this look ok?" -n 1 -r
+ echo
+ if [[ "$REPLY" =~ ^[Yy]$ ]]; then
+ command kubectl apply -k ./
+ fi
+ fi
+}
+
__k3s_login() {
# Copy k3s config
mkdir -p "$HOME/.kube"
sudo cp /etc/rancher/k3s/k3s.yaml "$HOME/.kube/config"
sudo chown "$(id -u):$(id -g)" "$HOME/.kube/config"
chmod 600 "$HOME/.kube/config"
echo "Export this: export KUBECONFIG=$HOME/.kube/config"
}
# Pull images as defined in helm chart.
# Pass in username and password for registry
# This currently only pulls the kolab images (for the rest we'd have to figure out where to pull from)
__k3s_pull() {
# Figure out which images to pull
images=$(__helm_template | grep "image: " | grep -v "#" | grep -oP "(?<=image: ).*" | sed 's/\"//g' | uniq )
for image in $images; do
echo "Pulling $image"
# For the quay.io/apheleiait images we need to pass in the credentials
# if [[ $image == *"quay.io/apheleiait"* ]]; then
# if [[ -z $1 || -z $2 ]]; then
# echo "You need to specify the quay.io/apheleiait username and password"
# exit 1
# fi
# sudo k3s ctr images pull --user "$1:$2" "$image"
# else
#TODO Support non apheleiait images?
sudo k3s ctr images pull "$image"
# fi
done
}
__k3s_cluster_install() {
sudo mkdir -p /etc/rancher/k3s/
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - --disable traefik,servicelb --write-kubeconfig-mode=644 --token=simple123 --datastore-endpoint="mysql://k3s:simple123@tcp(192.168.122.200:3306)/k3s" --tls-san=192.168.122.200
# curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - --disable traefik,servicelb --write-kubeconfig-mode=644 --token={{ k3s_token }} --datastore-endpoint="mysql://k3s:{{ k3s_db_password }}@tcp({{ virtual_ip }}:3306)/k3s" --tls-san=192.168.122.140 --tls-san=192.168.122.218 --tls-san=192.168.122.200 --cluster-cidr=10.0.0.0/16 --disable-network-policy --flannel-backend=none'
sudo chmod 644 /etc/rancher/k3s/k3s.yaml
cat <<EOF | kubectl create -f -
kind: StorageClass
apiVersion: storage.k8s.io/v1
metadata:
name: local-storage
provisioner: kubernetes.io/no-provisioner
volumeBindingMode: WaitForFirstConsumer
EOF
# Install Calico
# kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.3/manifests/tigera-operator.yaml
# cat <<EOF | kubectl create -f -
# # This section includes base Calico installation configuration.
# # For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.Installation
# apiVersion: operator.tigera.io/v1
# kind: Installation
# metadata:
# name: default
# spec:
# # Configures Calico networking.
# calicoNetwork:
# # Note: The ipPools section cannot be modified post-install.
# ipPools:
# - blockSize: 26
# cidr: 10.0.0.0/16
# encapsulation: VXLANCrossSubnet
# natOutgoing: Enabled
# nodeSelector: all()
# ---
# # This section configures the Calico API server.
# # For more information, see: https://projectcalico.docs.tigera.io/master/reference/installation/api#operator.tigera.io/v1.APIServer
# apiVersion: operator.tigera.io/v1
# kind: APIServer
# metadata:
# name: default
# spec: {}
# EOF
}
__k3s_install() {
sudo mkdir -p /etc/rancher/k3s/
curl -sfL https://get.k3s.io | INSTALL_K3S_EXEC="server" sh -s - --disable traefik,servicelb --write-kubeconfig-mode=644
sudo chmod 644 /etc/rancher/k3s/k3s.yaml
}
__k3s_setup() {
# Install certmanager
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.crds.yaml
helm repo add jetstack https://charts.jetstack.io
helm repo add haproxytech https://haproxytech.github.io/helm-charts
helm repo add prometheus-community https://prometheus-community.github.io/helm-charts
helm repo add metallb https://metallb.github.io/metallb
helm repo update
helm install cert-manager jetstack/cert-manager \
--wait \
--namespace cert-manager \
--create-namespace \
--version v1.13.3
helm install haproxy-ingress haproxytech/kubernetes-ingress \
--wait \
--namespace haproxy-controller \
--create-namespace \
--set controller.config.ssl-certificate=kolab/kolab-cert \
--set controller.kind=DaemonSet \
--set controller.daemonset.useHostPort=true \
--version 1.38.5
helm install kube-state-metrics prometheus-community/kube-state-metrics \
--wait \
--namespace default \
--version 3.0.0
helm install metallb metallb/metallb --create-namespace \
--namespace metallb-system --wait
}
__sum_memory_requests() {
res=$(kubectl get pods -o=jsonpath='{.items[*]..resources.requests.memory}' -n "$NAMESPACE")
let tot=0
for i in $res; do
if [[ $i =~ "Mi" ]]; then
i=$(echo $i | sed 's/[^0-9]*//g')
tot=$(( tot + i ))
elif [[ $i =~ "Gi" ]]; then
i=$(echo $i | sed 's/[^0-9]*//g')
tot=$(( tot + i * 1000 ))
fi
done
echo $tot
}
__sum_cpu_requests() {
res=$(kubectl get pods -o=jsonpath='{.items[*]..resources.requests.cpu}' -n "$NAMESPACE")
let tot=0
for i in $res; do
if [[ $i =~ "m" ]]; then
i=$(echo $i | sed 's/[^0-9]*//g')
tot=$(( tot + i ))
else
tot=$(( tot + i*1000 ))
fi
done
echo $tot
}
__replace_multiline() {
# Echo content, indent by the passed in spaces, insert before matching line
echo -n "$2" | sed -e "s/^/$4/" | sed -i "/$1/e cat /dev/stdin;echo" $3
# delete the matching line
sed -i "/$1/d" $3
}
### ========== End of Implementation ============
#
### ========== Commands ============
kolab__k3s-cluster-install() {
__k3s_cluster_install
}
kolab__k3s-setup() {
__k3s_setup
}
# Cluster admin commands
kolab__deploy() {
if [[ ! -f values.yaml ]]; then
echo "Missing a values.yaml file, run configure first."
exit 1
fi
if [[ "$1" == "--k3s" ]]; then
shift
__k3s_install
__k3s_setup
__k3s_pull $USERNAME $PASSWORD
# kolab__registry_login $USERNAME $PASSWORD
fi
if [[ -f /etc/rancher/k3s/k3s.yaml ]]; then
# Shouldn't be necessary but seems to be in the vm case
sudo chmod 644 /etc/rancher/k3s/k3s.yaml
fi
if [[ "$1" != "--prepare" ]]; then
shift
__ensure_server
echo "This is going to take a while (timeout after 30 minutes)"
__helm_upgrade
fi
}
kolab__uninstall() {
command helm uninstall kolab --wait --timeout 10m0s --debug $ARGS $@ --namespace "$NAMESPACE"
}
kolab__update() {
__helm_upgrade $@
}
kolab__template() {
__helm_template $@
}
kolab__pull() {
__k3s_pull $@
}
kolab__generate_local_cert() {
name="$1"
if [[ -z $name ]]; then
echo "Pass domain to generate the certificate for"
exit 1
fi
cert_dir=${CERT_DIR:-${PWD}/certs/}
if [ ! -d "${cert_dir}" ]; then
mkdir -p ${cert_dir}
fi
if [ ! -f "${cert_dir}/ca.key" ]; then
openssl genrsa -out ${cert_dir}/ca.key 4096
openssl req \
-new \
-x509 \
-nodes \
-days 3650 \
-key ${cert_dir}/ca.key \
-out ${cert_dir}/ca.cert \
-subj '/O=Example CA/'
# Trust the new ca
sudo trust anchor --store certs/ca.cert
sudo update-ca-trust
fi
if [ -f /etc/pki/tls/openssl.cnf ]; then
openssl_cnf="/etc/pki/tls/openssl.cnf"
elif [ -f /etc/ssl/openssl.cnf ]; then
openssl_cnf="/etc/ssl/openssl.cnf"
else
echo "No openssl.cnf"
exit 1
fi
openssl genrsa -out ${cert_dir}/${name}.key 4096
SAN="[SAN]\nsubjectAltName=DNS:${name},DNS:admin.${name},DNS:services.${name}"
openssl req \
-new \
-key ${cert_dir}/${name}.key \
-out ${cert_dir}/${name}.csr \
-subj "/O=Example CA/CN=${name}/" \
-reqexts SAN \
-config <(cat ${openssl_cnf} \
<(printf $SAN))
openssl x509 \
-req \
-in ${cert_dir}/${name}.csr \
-CA ${cert_dir}/ca.cert \
-CAkey ${cert_dir}/ca.key \
-CAcreateserial \
-out ${cert_dir}/${name}.cert \
-days 28 \
-extfile <(cat ${openssl_cnf} \
<(printf $SAN)) \
-extensions SAN
cat ${cert_dir}/${name}.cert \
${cert_dir}/ca.cert > ${cert_dir}/${name}.chain.pem
chmod 644 ${cert_dir}/*.{cert,key,pem}
}
# Update the kolabctl script from the latest tarball
kolab__selfupdate() {
wget https://mirror.apheleia-it.ch/pub/kolab-kubernetes-latest.tar.gz -O /tmp/kolab-kubernetes-latest.tar.gz
tar -zxvf /tmp/kolab-kubernetes-latest.tar.gz kolabctl
}
# kolab__backup() {
# command bin/backup.sh
# }
# kolab__restore() {
# command bin/restore.sh
# }
# Render a values.yaml file from a template in docs
kolab__configure() {
if [[ -z $TEMPLATE ]]; then
if [[ "$1" == "--openshift" ]]; then
TEMPLATE="deployments/openshift-cluster/values.yaml"
else
TEMPLATE="deployments/single-node/values.yaml"
fi
fi
if [[ -f values.yaml ]]; then
echo "values.yaml already exists";
exit 1
fi
if [[ -z $DOMAIN ]]; then
echo "Please enter your domain:"
read -r DOMAIN
fi
if [[ -z $ADMIN_PASSWORD ]]; then
echo "Please enter your new admin password for the admin@$DOMAIN user:"
read -r ADMIN_PASSWORD
fi
if [[ "$1" == "--openshift" ]]; then
if [[ -z $POSTFIX_LOADBALANCER_IP ]]; then
echo "Please enter your postfix loadbalancer ip:"
read -r POSTFIX_LOADBALANCER_IP
fi
if [[ -z $PROXY_LOADBALANCER_IP ]]; then
echo "Please enter your proxy loadbalancer ip:"
read -r PROXY_LOADBALANCER_IP
fi
if [[ -z $MEET_LOADBALANCER_IP ]]; then
echo "Please enter your meet loadbalancer ip:"
read -r MEET_LOADBALANCER_IP
fi
if [[ -z $METALLB_ADDRESS_POOL ]]; then
echo "Please enter your metallb address pool:"
read -r METALLB_ADDRESS_POOL
fi
if [[ -z $STORAGE_CLASS ]]; then
echo "Please enter your storage class (e.g. ocs-storagecluster-ceph-rbd):"
read -r STORAGE_CLASS
fi
else
# Assamble the docker secret, which will be our pull secret
PULL_SECRET=$(
cat <<EOF | base64 -w0
{
"auths": {
"quay.io": {
"auth": "$(echo -n "$USERNAME:$PASSWORD" | base64 -w0)",
"email": ""
}
}
}
EOF
)
fi
if [[ -z $PUBLIC_IP ]]; then
echo "Please enter your public ip:"
read -r PUBLIC_IP
else
echo "Using public ip: $PUBLIC_IP"
fi
# Generate secrets
[ -z $TEST_PASSWORD ] && TEST_PASSWORD=$(openssl rand -base64 24)
[ -z $APP_KEY ] && APP_KEY="base64:$(openssl rand -base64 32)"
[ -z $COTURN_STATIC_SECRET ] && COTURN_STATIC_SECRET=$(openssl rand -hex 32)
[ -z $PASSPORT_PROXY_OAUTH_CLIENT_ID ] && PASSPORT_PROXY_OAUTH_CLIENT_ID=$(uuidgen)
[ -z $PASSPORT_PROXY_OAUTH_CLIENT_SECRET ] && PASSPORT_PROXY_OAUTH_CLIENT_SECRET=$(openssl rand -base64 32)
[ -z $PASSPORT_WEBMAIL_SSO_CLIENT_ID ] && PASSPORT_WEBMAIL_SSO_CLIENT_ID=$(uuidgen)
[ -z $PASSPORT_WEBMAIL_SSO_CLIENT_SECRET ] && PASSPORT_WEBMAIL_SSO_CLIENT_SECRET=$(openssl rand -base64 32)
[ -z "$PASSPORT_PRIVATE_KEY" ] && PASSPORT_PRIVATE_KEY=$(openssl genrsa 4096)
PASSPORT_PUBLIC_KEY=$(echo "$PASSPORT_PRIVATE_KEY" | openssl rsa -pubout 2>/dev/null)
[ -z $MEET_WEBHOOK_TOKEN ] && MEET_WEBHOOK_TOKEN=$(openssl rand -hex 32)
[ -z $MEET_SERVER_TOKEN ] && MEET_SERVER_TOKEN=$(openssl rand -hex 32)
MEET_PUBLIC_IP="$PUBLIC_IP"
[ -z $DB_ROOT_PASSWORD ] && DB_ROOT_PASSWORD=$(openssl rand -hex 16)
[ -z $DB_KOLAB_PASSWORD ] && DB_KOLAB_PASSWORD=$(openssl rand -hex 16)
[ -z $DB_LEGACY_PASSWORD ] && DB_LEGACY_PASSWORD=$(openssl rand -hex 16)
[ -z $DB_ROUNDCUBE_PASSWORD ] && DB_ROUNDCUBE_PASSWORD=$(openssl rand -hex 16)
[ -z $DB_MONITORING_PASSWORD ] && DB_MONITORING_PASSWORD=$(openssl rand -hex 16)
[ -z $REDIS_PASSWORD ] && REDIS_PASSWORD=$(openssl rand -hex 16)
[ -z $MAIL_NOREPLY_PASSWORD ] && MAIL_NOREPLY_PASSWORD=$(openssl rand -hex 16)
[ -z $MINIO_ROOT_PASSWORD ] && MINIO_ROOT_PASSWORD=$(openssl rand -hex 16)
[ -z $IMAP_ADMIN_PASSWORD ] && IMAP_ADMIN_PASSWORD=$(openssl rand -hex 16)
[ -z $ROUNDCUBE_DES_KEY ] && ROUNDCUBE_DES_KEY=$(openssl rand -base64 24)
[ -z $EXTERNAL_SERVICE_USER_PASSWORD ] && EXTERNAL_SERVICE_USER_PASSWORD=$(openssl passwd -1 $ADMIN_PASSWORD);
DKIM_IDENTIFIER="dkim20240318";
[ -z "$DKIM_KEY" ] && DKIM_KEY=$(openssl genrsa 2048);
cp "$TEMPLATE" values.yaml
# / can appear in base64, but | not
sed -i \
-e "s|DOMAIN|${DOMAIN}|g" \
-e "s|TEST_PASSWORD|${TEST_PASSWORD}|g" \
-e "s|IMAP_ADMIN_PASSWORD|${IMAP_ADMIN_PASSWORD}|g" \
-e "s|APP_KEY|${APP_KEY}|g" \
-e "s|IMAGE_REGISTRY|${IMAGE_REGISTRY}|g" \
-e "s|IMAGE_VERSION|${IMAGE_VERSION}|g" \
-e "s|PULL_SECRET|${PULL_SECRET}|g" \
-e "s|PASSPORT_PROXY_OAUTH_CLIENT_ID|${PASSPORT_PROXY_OAUTH_CLIENT_ID}|g" \
-e "s|PASSPORT_PROXY_OAUTH_CLIENT_SECRET|${PASSPORT_PROXY_OAUTH_CLIENT_SECRET}|g" \
-e "s|PASSPORT_WEBMAIL_SSO_CLIENT_ID|${PASSPORT_WEBMAIL_SSO_CLIENT_ID}|g" \
-e "s|PASSPORT_WEBMAIL_SSO_CLIENT_SECRET|${PASSPORT_WEBMAIL_SSO_CLIENT_SECRET}|g" \
-e "s|ROUNDCUBE_DES_KEY|${ROUNDCUBE_DES_KEY}|g" \
-e "s|MEET_WEBHOOK_TOKEN|${MEET_WEBHOOK_TOKEN}|g" \
-e "s|MEET_SERVER_TOKEN|${MEET_SERVER_TOKEN}|g" \
-e "s|MEET_PUBLIC_IP|${MEET_PUBLIC_IP}|g" \
-e "s|COTURN_STATIC_SECRET|${COTURN_STATIC_SECRET}|g" \
-e "s|DB_ROOT_PASSWORD|${DB_ROOT_PASSWORD}|g" \
-e "s|DB_KOLAB_PASSWORD|${DB_KOLAB_PASSWORD}|g" \
-e "s|DB_LEGACY_PASSWORD|${DB_LEGACY_PASSWORD}|g" \
-e "s|DB_ROUNDCUBE_PASSWORD|${DB_ROUNDCUBE_PASSWORD}|g" \
-e "s|DB_MONITORING_PASSWORD|${DB_MONITORING_PASSWORD}|g" \
-e "s|DB_HOST|${DB_HOST}|g" \
-e "s|REDIS_PASSWORD|${REDIS_PASSWORD}|g" \
-e "s|MAIL_NOREPLY_PASSWORD|${MAIL_NOREPLY_PASSWORD}|g" \
-e "s|MINIO_ROOT_PASSWORD|${MINIO_ROOT_PASSWORD}|g" \
-e "s|DKIM_IDENTIFIER|${DKIM_IDENTIFIER}|g" \
-e "s|ADMIN_PASSWORD|${ADMIN_PASSWORD}|g" \
-e "s|PUBLIC_IP|${PUBLIC_IP}|g" \
-e "s|STORAGE_CLASS|${STORAGE_CLASS}|g" \
-e "s|MEET_LOADBALANCER_IP|${MEET_LOADBALANCER_IP}|g" \
-e "s|PROXY_LOADBALANCER_IP|${PROXY_LOADBALANCER_IP}|g" \
-e "s|POSTFIX_LOADBALANCER_IP|${POSTFIX_LOADBALANCER_IP}|g" \
-e "s|METALLB_ADDRESS_POOL|${METALLB_ADDRESS_POOL}|g" \
-e "s|EXTERNAL_SERVICE_USER_PASSWORD|${EXTERNAL_SERVICE_USER_PASSWORD}|g" \
values.yaml
__replace_multiline PASSPORT_PRIVATE_KEY "$PASSPORT_PRIVATE_KEY" values.yaml " "
__replace_multiline PASSPORT_PUBLIC_KEY "$PASSPORT_PUBLIC_KEY" values.yaml " "
__replace_multiline DKIM_KEY "$DKIM_KEY" values.yaml " "
if [[ "$1" != "--openshift" ]]; then
# Default to a static local cert
kolab__generate_local_cert "$HOST"
[ -z "$TLS_CERT" ] && TLS_CERT=$(cat certs/$HOST.cert)
[ -z "$TLS_KEY" ] && TLS_KEY=$(cat certs/$HOST.key)
__replace_multiline TLS_CERT "$TLS_CERT" values.yaml " "
__replace_multiline TLS_KEY "$TLS_KEY" values.yaml " "
fi
echo "generated values.yaml successfully"
}
# Re-render values.yaml, but preserve secrets
kolab__reconfigure() {
if [[ -f values.yaml ]]; then
# Load all secrets from the existing values.yaml file (except the once that we expect to be set already)
export TEST_PASSWORD=$(yq '.serviceAccounts.monitoring1.password' values.yaml)
export APP_KEY=$(yq '.appKey' values.yaml)
# export COTURN_STATIC_SECRET=(yq '.appKey' values.yaml)
export PASSPORT_PROXY_OAUTH_CLIENT_ID=$(yq '.passport.proxyOauthClientId' values.yaml)
export PASSPORT_PROXY_OAUTH_CLIENT_SECRET=$(yq '.passport.proxyOauthClientSecret' values.yaml)
export PASSPORT_WEBMAIL_SSO_CLIENT_ID=$(yq '.passport.webmailSSOClientId' values.yaml)
export PASSPORT_WEBMAIL_SSO_CLIENT_SECRET=$(yq '.passport.webmailSSOClientSecret' values.yaml)
export PASSPORT_PRIVATE_KEY="$(yq '.passport.privateKey' values.yaml)"
export MEET_WEBHOOK_TOKEN=$(yq '.meet.webhookToken' values.yaml)
export MEET_SERVER_TOKEN=$(yq '.meet.serverToken' values.yaml)
# [ -z $DB_ROOT_PASSWORD ] && DB_ROOT_PASSWORD=$(openssl rand -hex 16)
# [ -z $DB_KOLAB_PASSWORD ] && DB_KOLAB_PASSWORD=$(openssl rand -hex 16)
export DB_LEGACY_PASSWORD=$(yq '.mariadb.kolabLegacyPassword' values.yaml)
# [ -z $DB_ROUNDCUBE_PASSWORD ] && DB_ROUNDCUBE_PASSWORD=$(openssl rand -hex 16)
# [ -z $DB_MONITORING_PASSWORD ] && DB_MONITORING_PASSWORD=$(openssl rand -hex 16)
export REDIS_PASSWORD=$(yq '.redis.password' values.yaml)
export MAIL_NOREPLY_PASSWORD=$(yq '.mail.noreplyPassword' values.yaml)
export MINIO_ROOT_PASSWORD=$(yq '.minio.rootPassword' values.yaml)
export IMAP_ADMIN_PASSWORD=$(yq '.imap.adminPassword' values.yaml)
export ROUNDCUBE_DES_KEY=$(yq '.roundcube.desKey' values.yaml)
export EXTERNAL_SERVICE_USER_PASSWORD=$(yq '.externalServiceUserPassword' values.yaml)
export DKIM_KEY="$(yq '.amavis.dkim.key' values.yaml)"
export TLS_CERT="$(yq '.tlsSecret.crt' values.yaml)"
export TLS_KEY="$(yq '.tlsSecret.key' values.yaml)"
mv values.yaml values.yaml.backup
fi
kolab__configure $@
rm -f values.yaml.backup
}
kolab__enable_letsencrypt() {
sed -i \
-e "s/kolab-cert-static/kolab-cert-letsencrypt/g" \
-e "s/type: static/type: letsencrypt/g" \
values.yaml
yq e -i '.certManager.letsencryptIssuer = true' values.yaml
__helm_upgrade
}
kolab__update_public_ip() {
sed -i \
-e "s/publicIp: .*/publicIp: $PUBLIC_IP/g" \
values.yaml
__helm_upgrade
}
kolab__registry_login() {
helm registry login quay.io/apheleiait -u "$1" -p "$2"
}
__wait_for_service() {
echo "Waiting for service/$1"
# Wait for the ingress section with the assigned ip to appear
command timeout 10s bash -c "until kubectl -n kolab get service/$1 --output=jsonpath='{.status.loadBalancer}' | grep 'ingress'; do : ; done" || :
if command kubectl -n kolab get service/external-proxy --output=jsonpath='{.status.loadBalancer}' | grep "ingress"; then
echo "Service $1 is bound";
else
echo "Service $1 does not have an external ip";
exit 1;
fi
}
kolab__selfcheck() {
set -e
if command kubectl -n $NAMESPACE describe secret/kolab-cert-static --request-timeout "5s" &> /dev/null; then
echo "Found static tls secret"
elif command kubectl -n $NAMESPACE describe secret/kolab-cert-letsencrypt --request-timeout "5s" &> /dev/null; then
echo "Found letsencrypt secret"
else
echo "TLS secret not found"
exit 1
fi
# Wait for all rollouts to complete
command kubectl -n $NAMESPACE rollout status deployment
__wait_for_service "external-proxy"
__wait_for_service "external-smtp"
# Check that all pvcs are available
for pvc in $(kubectl -n kolab get --no-headers=true pvc -o name); do
command kubectl -n kolab wait --for=jsonpath='{.status.phase}'=Bound $pvc
done
command helm status kolab -n $NAMESPACE | grep "STATUS: deployed"
command kubectl exec --stdin --tty -n "$NAMESPACE" deployment/imap -- bash -c "testsaslauthd -u \$IMAP_ADMIN_LOGIN -p \$IMAP_ADMIN_PASSWORD"
command kubectl exec --stdin --tty -n "$NAMESPACE" deployment/horizon -- ./artisan status:health --check=Redis --check=IMAP
command kubectl exec --stdin --tty -n "$NAMESPACE" deployment/roundcube -- ./checkconnections.sh
echo "All tests passed"
}
kolab__stop() {
command /usr/local/bin/k3s-killall.sh
}
kolab__start() {
command systemctl start k3s
}
kolab__status() {
echo "# Cluster info"
command kubectl cluster-info
echo "# Helm deployments"
command helm list -A
echo "# Helm status"
command helm status kolab -n "$NAMESPACE" --show-resources
echo "# Events"
command kubectl get events --sort-by=.metadata.creationTimestamp
}
kolab__shell() {
if [[ $1 == "" ]]; then
# command kubectl run kolab -ti --rm -n "$NAMESPACE" --image localhost:5000/webapp:latest -- /bin/bash
command kubectl run utils -ti --rm -n "$NAMESPACE" --image quay.io/apheleiait/kolab/utils:latest -- /bin/bash
else
deployment=$1
shift
command kubectl exec --stdin --tty -n "$NAMESPACE" "deployment/$deployment" $@ -- /bin/bash
fi
}
kolab__logs() {
if [[ "$1" == "monitoring" ]]; then
# FIXME we should have a label to select on
command kubectl -n "$NAMESPACE" logs $(oc get pods --no-headers=true | grep "monitoring" | cut -d' ' -f 1 | head -1)
elif [[ "$1" == "scheduler" ]]; then
# FIXME we should have a label to select on
for i in $(oc get pods --no-headers=true | grep "scheduler" | cut -d' ' -f 1); do
command kubectl -n "$NAMESPACE" logs "$i"
done
else
deployment="$1"
shift
command kubectl -n "$NAMESPACE" logs "deployment/$deployment" $@
fi
}
# Tail the logs via logcli
# --pod=: wildcard match on the pod_name label
# --search=: Run a fulltext query match on the record
# -f: Stream the log
# --full: Full output including the entire record
kolab__tail() {
if [[ "$*" =~ "--pod" ]]; then
ARGUMENT=$(echo "$*" | grep -o -e "--pod=.*" | cut -d ' ' -f 1)
POD_NAME=$(echo "$ARGUMENT" | cut -d '=' -f 2)
POD_FILTER=",pod_name=~\"$POD_NAME.*\""
set -- "$(echo "$*" | sed "s|$ARGUMENT *||")"
fi
if [[ "$*" =~ "--search" ]]; then
ARGUMENT=$(echo "$*" | grep -o -e "--search=.*" | cut -d ' ' -f 1)
SEARCH_STRING=$(echo "$ARGUMENT" | cut -d '=' -f 2)
FULLTEXT_FILTER=" |~ \"$SEARCH_STRING\""
set -- "$(echo "$*" | sed "s|$ARGUMENT *||")"
fi
if [[ "$*" =~ "--full" ]]; then
set -- "$(echo "$*" | sed "s|--full *||")"
else
OUTPUT="--output=raw"
fi
echo "$*"
if [[ "$*" =~ "-f" ]]; then
FOLLOW="--follow"
fi
# The format is --from=2024-02-22T08:30:24Z --to=2024-02-23T12:30:24Z
if [[ "$*" =~ "--from" ]]; then
# Can't have --from without --to
FROM=$(echo "$*" | grep -o -e "--from=.*" | cut -d ' ' -f 1)
TO=$(echo "$*" | grep -o -e "--to=.*" | cut -d ' ' -f 1)
#beware of --limit (it will continue to apply, so you may get partial results)
# Can't follow with a time range
FOLLOW=""
fi
QUERY="{namespace_name=\"$NAMESPACE\"$POD_FILTER} $FULLTEXT_FILTER | json log | line_format \"{{ __timestamp__ }} \t {{.pod_name | trunc 10}} \t{{.log}}\""
echo "Running query: $QUERY"
if [[ "$ADMIN_PASSWORD" == "" ]]; then
ADMIN_PASSWORD=$(cat values.yaml | yq '.adminPassword')
fi
env LOKI_ADDR=${LOKI_ADDR:-"http://admin.$HOST/"} logcli --username "admin" --password "$ADMIN_PASSWORD" query "$QUERY" $OUTPUT $FOLLOW $FROM $TO
}
kolab__describe() {
if [[ $1 == *"pod"* ]]; then
command kubectl -n "$NAMESPACE" describe $@
else
deployment="$1"
shift
command kubectl -n "$NAMESPACE" describe "deployment/$deployment" $@
fi
}
kolab__restart() {
if [[ $1 == "" ]]; then
command kubectl -n "$NAMESPACE" rollout restart deployment
else
command kubectl -n "$NAMESPACE" rollout restart deployment/$1
fi
}
kolab__ps() {
command kubectl -n "$NAMESPACE" get pods
}
kolab__get() {
command kubectl -n "$NAMESPACE" get $@
}
kolab__volumes() {
command kubectl -n "$NAMESPACE" get persistentvolumeclaims $@
}
kolab__build() {
command env REGISTRY="localhost:5000" build/build.sh --nochecks
}
kolab__top() {
command kubectl top pods -n "$NAMESPACE" --sum=true
command kubectl get pods -n "$NAMESPACE" -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t\t"}{..resources.requests.memory}{end}'
echo
echo
echo "Total memory requests: $(__sum_memory_requests) Mi"
echo "Total cpu requests: $(__sum_cpu_requests) m"
}
kolab__metrics() {
command kubectl get --raw /apis/metrics.k8s.io/v1beta1/pods | jq
command kubectl get --raw /apis/metrics.k8s.io/v1beta1/nodes | jq
# # Get the metrics for node <node_name>
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/<node_name> | jq '.'
# # Get the metrics for pode <pod_name>
# kubectl get --raw /apis/metrics.k8s.io/v1beta1/<pod_name> | jq '.'
}
kolab__reset() {
if [[ "$1" == "--force" ]]; then
REPLY="y"
else
read -p "Are you sure? This will delete the k3s cluster including all data" -n 1 -r
echo
fi
if [[ "$REPLY" =~ ^[Yy]$ ]];
then
/usr/local/bin/k3s-uninstall.sh
fi
}
kolab__login() {
if [[ "$1" == "--k3s" ]]; then
__k3s_login
else
echo "Configure kubectl manually, login is not implemented"
fi
command kubectl cluster-info
}
kolab__exec() {
container=$1
shift
command kubectl exec -q --stdin --tty -n "$NAMESPACE" "deployment/$container" -- $@
}
kolab__run() {
container=$1
shift
IMAGE=$(kubectl get deployment/$container -o jsonpath="{..image}")
command kubectl run $container --image $IMAGE -ti --rm --restart=Never --command -- $@
}
# Administration commands
kolab__cyradm() {
ADMIN_PASSWORD=$(cat values.yaml | yq '.imap.adminPassword')
kolab__exec imap cyradm --auth PLAIN -u cyrus-admin -w "$ADMIN_PASSWORD" --port 11143 localhost
}
kolab__reseed() {
read -p "Are you sure? This will delete all data" -n 1 -r
echo
if [[ "$REPLY" =~ ^[Yy]$ ]];
then
kolab__exec horizon ./artisan migrate:fresh --seed
fi
}
kolab__users() {
kolab__exec horizon ./artisan users --attr=email
}
kolab__create-user() {
kolab__exec horizon ./artisan user:create $@
}
# Run imapcli commands
# ci/testctl imapcli admin@kolab.local simple123 fetch --debug INBOX 1001
# ci/testctl imapcli admin@kolab.local simple123 tag INBOX 1000..2000 foobar
# ci/testctl imapcli admin@kolab.local simple123 getacl INBOX
kolab__imapcli() {
USER=$1
PASSWORD=$2
CMD=$3
shift
shift
shift
kolab__run utils ./imapcli.rb "$CMD" --host imap --port 143 --username $USER --password "$PASSWORD" "$@"
}
# Generate mail in the admin inbox:
# generate-mail admin@kolab.local simple123 --clear --maxAttachmentSize=0 --type=mail --count 500 INBOX
kolab__generate-mail() {
USER=$1
PASSWORD=$2
CMD=$3
shift
shift
shift
kolab__run utils ./generatemail.py --host imap --port 143 --username $USER --password "$PASSWORD" $@
}
kolab__generate-users() {
for usernum in $(seq 1 100) ; do
USER="testuser$usernum@kolab.local"
kolab__create-user $USER --password simple123
kolab__generate-mail $USER simple123 --clear --maxAttachmentSize=0 --type=mail --count 1000 INBOX
for i in $(seq 1 20) ; do
kolab__imapcli $USER simple123 tag INBOX 1:999 "rctag$i"
done
done
}
kolab__diskusage() {
echo
echo "IMAP:"
kolab__exec imap du -h /var/spool/imap/ -d 0
kolab__exec imap du -h /var/lib/imap/ -d 0
kolab__exec imap df -ah | grep imap
echo
echo "Postfix:"
kolab__exec postfix du -h /var/spool/postfix/ -d 0
kolab__exec postfix df -ah | grep postfix
# For monitoring kubelet_volume_stats_available_bytes
}
kolab__password() {
kolab__exec horizon ./artisan user:password $@
}
kolab__db() {
kolab__exec mariadb mysql -p
}
kolab__cleanup() {
kubectl -n $NAMESPACE delete pod --field-selector=status.phase==Succeeded
kubectl -n $NAMESPACE delete pod --field-selector=status.phase==Failed
}
# Show dns configuration based on values.yaml values
kolab__dns() {
PUBLIC_IP=$(cat values.yaml | yq '.meet.publicIp')
DOMAIN=$(cat values.yaml | yq '.domainName')
EMAILDOMAIN=$DOMAIN
DKIM_IDENTIFIER=$(cat values.yaml | yq '.amavis.dkim.identifier')
# Extract public key from private key, remove delimiters and add quotation marks on each line. Finally indent result
DKIM_PUBLIC_KEY=$(cat values.yaml | yq '.amavis.dkim.key' | openssl pkey -pubout | grep --invert-match "\----" | sed -e 's/^\|$/"/g' | sed 's/^/ /';)
echo
echo "DNS Configuration:"
echo
cat <<EOF
$DOMAIN A $PUBLIC_IP
$EMAILDOMAIN MX 10 $DOMAIN.
$EMAILDOMAIN TXT "v=spf1 mx a:$DOMAIN mx:$DOMAIN -all"
autodiscover.$EMAILDOMAIN CNAME $DOMAIN.
_autodiscover._tcp.$DOMAIN SRV 0 0 443 $DOMAIN.
_caldav._tcp.$DOMAIN SRV 0 0 80 $DOMAIN.
_caldavs._tcp.$DOMAIN SRV 0 1 443 $DOMAIN.
_carddav._tcp.$DOMAIN SRV 0 0 80 $DOMAIN.
_carddavs._tcp.$DOMAIN SRV 0 1 443 $DOMAIN.
_imap._tcp.$DOMAIN SRV 0 0 143 $DOMAIN.
_imaps._tcp.$DOMAIN SRV 0 1 993 $DOMAIN.
_pop3._tcp.$DOMAIN SRV 10 0 110 $DOMAIN.
_pop3s._tcp.$DOMAIN SRV 10 1 995 $DOMAIN.
_sieve._tcp.$DOMAIN SRV 0 0 4190 $DOMAIN.
_smtp._tcp.$DOMAIN TXT "v=TLSRPTv1; rua=mailto:admin@$DOMAIN"
_submission._tcp.$DOMAIN SRV 0 1 587 $DOMAIN.
_webdav._tcp.$DOMAIN SRV 0 0 80 $DOMAIN.
_webdavs._tcp.$DOMAIN SRV 0 1 443 $DOMAIN.
_dmarc.$DOMAIN TXT "v=DMARC1; p=quarantine; adkim=s; aspf=s; rua=mailto:admin@$DOMAIN; ruf=mailto:admin@$DOMAIN"
mta-sts.$DOMAIN CNAME $DOMAIN.
_mta-sts.$DOMAIN TXT "v=STSv1; id=2024031901;"
$DKIM_IDENTIFIER._domainkey.$DOMAIN TXT (
"v=DKIM1; p="
$DKIM_PUBLIC_KEY
)
EOF
}
kolab__help() {
cat <<EOF
This is the kolab commandline utility.
The following commands are available:
deploy: Deploy kolab
start: Start all containers
stop: Stop all containers
update: This will update all containers.
backup: Create a backup in backup/
restore: Restore a backup from backup/
selfcheck: Run a selfcheck to ensure kolab is functional
EOF
}
cmdname=$1
shift
if [[ "${cmdname}" != "deploy" && "${cmdname}" != "configure" && "${cmdname}" != "reconfigure" && "${cmdname}" != "login" && "${cmdname}" != "tail" && "${cmdname}" != "stop" ]]; then
__ensure_server
fi
# make sure we actually *did* get passed a valid function name
if declare -f "kolab__$cmdname" >/dev/null 2>&1; then
"kolab__$cmdname" "${@:1}"
else
echo "Function $cmdname not recognized" >&2
kolab__help
exit 1
fi

File Metadata

Mime Type
text/x-diff
Expires
Mon, Apr 6, 1:18 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831827
Default Alt Text
(33 KB)

Event Timeline