Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117884264
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
33 KB
Referenced Files
None
Subscribers
None
View Options
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
Details
Attached
Mime Type
text/x-diff
Expires
Mon, Apr 6, 1:18 AM (1 d, 7 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
18831827
Default Alt Text
(33 KB)
Attached To
Mode
R114 kolab-infrastructure
Attached
Detach File
Event Timeline