Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F117747304
kolabctl
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Authored By
Unknown
Size
36 KB
Referenced Files
None
Subscribers
None
kolabctl
View Options
#!/bin/bash
# shellcheck disable=SC2068
# shellcheck disable=SC2086
# shellcheck disable=SC2001
# shellcheck disable=SC2002
# shellcheck disable=SC2219
# shellcheck disable=SC2059
# shellcheck disable=SC2155
NAMESPACE
=
${
NAMESPACE
:-
kolab
}
CHART_VERSION
=
${
CHART_VERSION
:-
"4.0.16"
}
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.16"
}
export
KUBECONFIG
=
${
KUBECONFIG
:-
"
$HOME
/.kube/config"
}
[
-f kubeconfig.yaml
]
&&
export
KUBECONFIG
=
"kubeconfig.yaml"
cert_dir
=
${
CERT_DIR
:-
${
PWD
}
/certs/
}
if
!
command
-v yq >/dev/null
2
>
&
1
then
echo
"yq could not be found"
exit
1
fi
### ========== 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
[[
"
$1
"
=
~
"--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
[
$DISABLE_CERT_MANAGER
!
=
"true"
]
&&
kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.13.3/cert-manager.crds.yaml
[
$DISABLE_CERT_MANAGER
!
=
"true"
]
&&
helm repo add jetstack https://charts.jetstack.io
[
-z
$DISABLE_INGRESS
]
&&
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
if
[[
$DISABLE_CERT_MANAGER
!
=
"true"
]]
;
then
helm install cert-manager jetstack/cert-manager
\
--wait
\
--namespace cert-manager
\
--create-namespace
\
--version v1.13.3
fi
if
[[
$DISABLE_INGRESS
!
=
"true"
]]
;
then
export
TLS_SECRET
=
$(
yq
'.tlsSecret.name'
values.yaml
)
# HAPROXY_CONTROLLER_ARGS="--set controller.image.tag=latest --set controller.image.repository=apheleiait/haproxytech/kubernetes-ingress"
helm install haproxy-ingress haproxytech/kubernetes-ingress
\
--wait
\
--namespace haproxy-controller
\
--create-namespace
\
--set controller.config.ssl-certificate
=
$TLS_SECRET
\
--set controller.kind
=
DaemonSet
\
--set controller.daemonset.useHostPort
=
true
\
$HAPROXY_CONTROLLER_ARGS
--version
1
.38.5
# Delete existing ingressclass, otherwise we can't apply our chart with the subcharts, which tries to create the same ingressclass
kubectl delete --ignore-not-found ingressclass/haproxy
fi
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
# Prepare the namespace
cat
<<EOF | kubectl apply -f -
apiVersion: v1
kind: Namespace
metadata:
name: kolab
EOF
# The ip address range just has to not conflict, it doesn't need to exist beforehand
cat
<<EOF | kubectl apply -f -
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: kolab-l2
namespace: metallb-system
spec:
addresses:
- 10.30.0.128/28
autoAssign: false
serviceAllocation:
priority: 50
serviceSelectors:
- matchLabels:
IPAddressPool: l2
namespaces:
- kolab
EOF
}
__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
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/k3s-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
=
"dkim1"
;
[
-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|PRIMARY_IP|
${
PRIMARY_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
"
$DOMAIN
"
[
-z
"
$TLS_CERT
"
]
&&
TLS_CERT
=
$(
cat certs/
$DOMAIN
.cert
)
[
-z
"
$TLS_KEY
"
]
&&
TLS_KEY
=
$(
cat certs/
$DOMAIN
.key
)
[
-z
"
$CA_CERT
"
]
&&
CA_CERT
=
$(
cat certs/ca.cert
)
__replace_multiline TLS_CERT
"
$TLS_CERT
"
values.yaml
" "
__replace_multiline TLS_KEY
"
$TLS_KEY
"
values.yaml
" "
__replace_multiline CA_CERT
"
$CA_CERT
"
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
)
export
DB_ROOT_PASSWORD
=
$(
yq
'.mariadb.rootPassword'
values.yaml
)
export
DB_KOLAB_PASSWORD
=
$(
yq
'.mariadb.kolabPassword'
values.yaml
)
export
DB_LEGACY_PASSWORD
=
$(
yq
'.mariadb.kolabLegacyPassword'
values.yaml
)
export
DB_ROUNDCUBE_PASSWORD
=
$(
yq
'.mariadb.roundcubePassword'
values.yaml
)
# [ -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
)
"
mv values.yaml values.yaml.backup
fi
# Reset so we can insert the cert again (in case it changed)
if
[[
"
$(
yq
'.tlsSecret.type'
values.yaml
)
"
==
"static"
]]
;
then
yq e -i
'.tlsSecret.crt = TLS_CERT'
values.yaml
yq e -i
'.tlsSecret.key = TLS_KEY'
values.yaml
yq e -i
'.tlsSecret.ca = CA_CERT'
values.yaml
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='{.spec.externalIPs[0]}' | grep -q ^; do : ; done"
||
:
if
command
kubectl -n kolab get service/external-proxy --output
=
jsonpath
=
'{.spec.externalIPs[0]}'
|
grep -q ^
;
then
echo
"Service
$1
is bound"
;
else
echo
"Service
$1
does not have an external ip"
;
exit
1
;
fi
}
kolab__connectiontest
()
{
set
-e
if
[[
-f values.yaml
]]
;
then
export
DOMAIN
=
$(
yq
'.domainName'
values.yaml
)
fi
for
port
in
25
143
443
465
587
993
44444
44445
44446
;
do
echo
"Testing
$port
over tcp"
nc -z
$DOMAIN
$port
done
echo
"All connections successful"
}
kolab__selfcheck
()
{
set
-e
if
[[
-f values.yaml
]]
;
then
export
DOMAIN
=
$(
yq
'.domainName'
values.yaml
)
fi
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
# Just a very complicated way to run a sql query because ./artisan db doesn't run queries.
# Also, we get a bunch of invisible characters, hence the tail and cut calls.
PRIMARY_DOMAIN_COUNT
=
"
$(
kolab__exec kolab ./artisan tinker --execute
"print(App\Domain::where('namespace','
$DOMAIN
')->count())"
|
tail -n
1
|
cut -c
1
-1
)
"
# Ensure seeding has completed (we verify the primary domain exists)
if
[[
"
$PRIMARY_DOMAIN_COUNT
"
==
"0"
]]
;
then
echo
"The domain
$DOMAIN
is not created, did seeding fail?"
exit
1
fi
__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
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
}
kolab__logcli
()
{
if
[[
-f values.yaml
]]
;
then
DOMAIN
=
$(
yq
'.domainName'
values.yaml
)
fi
if
[[
"
$ADMIN_PASSWORD
"
==
""
]]
;
then
ADMIN_PASSWORD
=
$(
yq
'.adminPassword'
values.yaml
)
fi
env
LOKI_ADDR
=
${
LOKI_ADDR
:-
"http://admin.
$DOMAIN
/"
}
logcli --username
"admin"
--password
"
$ADMIN_PASSWORD
"
"
$@
"
}
# 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
[[
"
$*
"
=
~
"--container"
]]
;
then
ARGUMENT
=
$(
echo
"
$*
"
|
grep -o -e
"--container=.*"
|
cut -d
' '
-f
1
)
CONTAINER_NAME
=
$(
echo
"
$ARGUMENT
"
|
cut -d
'='
-f
2
)
CONTAINER_FILTER
=
",container_name=~\"
$CONTAINER_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$CONTAINER_FILTER
}
$FULLTEXT_FILTER
| json log | line_format \"{{ __timestamp__ }} \t {{.pod_name | trunc 10}} \t{{.log}}\""
echo
"Running query:
$QUERY
"
kolab__logcli 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__enable-roundcube-debug
()
{
kolab__exec roundcube mkdir -m
777
-p
"roundcubemail/logs/
$1
"
kolab__exec roundcube mkdir -m
777
-p
"syncroton/logs/
$1
"
echo
"Created log marker directory for
$1
"
}
kolab__disable-roundcube-debug
()
{
kolab__exec roundcube rm -rf
"roundcubemail/logs/
$1
"
kolab__exec roundcube rm -rf
"syncroton/logs/
$1
"
echo
"Removed log marker directory for
$1
"
}
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.
_submission._tcp.$DOMAIN SRV 0 1 587 $DOMAIN.
_webdav._tcp.$DOMAIN SRV 0 0 80 $DOMAIN.
_webdavs._tcp.$DOMAIN SRV 0 1 443 $DOMAIN.
_smtp._tls.$DOMAIN TXT "v=TLSRPTv1; rua=mailto:admin@$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-shellscript
Expires
Apr 4 2026, 12:16 AM (4 w, 2 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
7e/86/832f25d669ee22712f689e2328fd
Default Alt Text
kolabctl (36 KB)
Attached To
Mode
R114 kolab-infrastructure
Attached
Detach File
Event Timeline