Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
209 changes: 209 additions & 0 deletions bin/helm-operations.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
#!/usr/bin/env bash
# shellcheck disable=SC2087
set -Eeo pipefail

# Read values from environment variables with defaults
BASE_DIR="/wire-server-deploy"
TARGET_SYSTEM="example.dev"
CERT_MASTER_EMAIL="certmaster@${TARGET_SYSTEM}"

# this IP should match the DNS A record value for TARGET_SYSTEM
# assuming it to be the public address used by clients to reach public Address
HOST_IP=""
if [ -z "$HOST_IP" ]; then
HOST_IP=$(wget -qO- https://api.ipify.org)
fi

# picking a node for calling traffic (3rd kube worker node)
CALLING_NODE=$(kubectl get nodes --no-headers | tail -n 1 | awk '{print $1}')
if [[ -z "$CALLING_NODE" ]]; then
echo "Error: could not determine the last kube worker node via kubectl"
exit 1
fi

# Creates values.yaml from prod-values.example.yaml and secrets.yaml from prod-secrets.example.yaml
# Works on all chart directories in $BASE_DIR/values/
process_values() {

ENV=$1
TYPE=$2
charts=(fake-aws smtp rabbitmq databases-ephemeral reaper wire-server webapp account-pages team-settings smallstep-accomp ingress-nginx-controller nginx-ingress-services coturn sftd cert-manager)

if [[ "$ENV" != "prod" ]] || [[ -z "$TYPE" ]] ; then
echo "Error: This function only supports prod deployments with TYPE as values or secrets. ENV must be 'prod', got: '$ENV' and '$TYPE'"
exit 1
fi
timestp=$(date +"%Y%m%d_%H%M%S")

for chart in "${charts[@]}"; do
chart_dir="$BASE_DIR/values/$chart"
if [[ -d "$chart_dir" ]]; then
if [[ -f "$chart_dir/${ENV}-${TYPE}.example.yaml" ]]; then
if [[ ! -f "$chart_dir/${TYPE}.yaml" ]]; then
cp "$chart_dir/${ENV}-${TYPE}.example.yaml" "$chart_dir/${TYPE}.yaml"
echo "Used template ${ENV}-${TYPE}.example.yaml to create $chart_dir/${TYPE}.yaml"
else
echo "$chart_dir/${TYPE}.yaml already exists, archiving it and creating a new one."
mv "$chart_dir/${TYPE}.yaml" "$chart_dir/${TYPE}.yaml.bak.$timestp"
cp "$chart_dir/${ENV}-${TYPE}.example.yaml" "$chart_dir/${TYPE}.yaml"
fi
fi
fi
done
}

# selectively setting values of following charts which requires additional values
# wire-server, webapp, team-settings, account-pages, nginx-ingress-services, sftd and coturn
configure_values() {

TEMP_DIR=$(mktemp -d)
trap 'rm -rf $TEMP_DIR' EXIT

# to find IP address of calling NODE
CALLING_NODE_IP=$(kubectl get node "$CALLING_NODE" -o jsonpath='{.status.addresses[?(@.type=="InternalIP")].address}')

# Fixing the hosts with TARGET_SYSTEM and setting the turn server
sed -e "s/example.com/$TARGET_SYSTEM/g" \
"$BASE_DIR/values/wire-server/values.yaml" > "$TEMP_DIR/wire-server-values.yaml"

# fixing the turnStatic values
yq eval -i ".brig.turnStatic.v2 = [\"turn:$HOST_IP:3478\", \"turn:$HOST_IP:3478?transport=tcp\"]" "$TEMP_DIR/wire-server-values.yaml"

# Fixing the hosts in webapp team-settings and account-pages charts
for chart in webapp team-settings account-pages; do
sed "s/example.com/$TARGET_SYSTEM/g" "$BASE_DIR/values/$chart/values.yaml" > "$TEMP_DIR/$chart-values.yaml"
done

# Setting certManager and DNS records
sed -e 's/useCertManager: false/useCertManager: true/g' \
-e "/certmasterEmail:$/s/certmasterEmail:/certmasterEmail: $CERT_MASTER_EMAIL/" \
-e "s/example.com/$TARGET_SYSTEM/" \
"$BASE_DIR/values/nginx-ingress-services/values.yaml" > "$TEMP_DIR/nginx-ingress-services-values.yaml"

# Fixing SFTD hosts and setting the cert-manager to http01
sed -e "s/webapp.example.com/webapp.$TARGET_SYSTEM/" \
-e "s/sftd.example.com/sftd.$TARGET_SYSTEM/" \
-e 's/name: letsencrypt-prod/name: letsencrypt-http01/' \
"$BASE_DIR/values/sftd/values.yaml" > "$TEMP_DIR/sftd-values.yaml"

# Setting coturn node IP values
yq eval -i ".coturnTurnListenIP = \"$CALLING_NODE_IP\"" "$BASE_DIR/values/coturn/values.yaml"
yq eval -i ".coturnTurnRelayIP = \"$CALLING_NODE_IP\"" "$BASE_DIR/values/coturn/values.yaml"
yq eval -i ".coturnTurnExternalIP = \"$HOST_IP\"" "$BASE_DIR/values/coturn/values.yaml"

# Compare and copy files if different
for file in wire-server-values.yaml webapp-values.yaml team-settings-values.yaml account-pages-values.yaml \
nginx-ingress-services-values.yaml sftd-values.yaml; do
if ! cmp -s "$TEMP_DIR/$file" "$BASE_DIR/values/${file%-values.yaml}/values.yaml"; then
cp "$TEMP_DIR/$file" "$BASE_DIR/values/${file%-values.yaml}/values.yaml"
echo "Updating $BASE_DIR/values/${file%-values.yaml}/values.yaml"
fi
done

}

deploy_charts() {

local charts=("$@")
echo "Following charts will be deployed: ${charts[*]}"

for chart in "${charts[@]}"; do
chart_dir="$BASE_DIR/charts/$chart"
values_file="$BASE_DIR/values/$chart/values.yaml"
secrets_file="$BASE_DIR/values/$chart/secrets.yaml"

if [[ ! -d "$chart_dir" ]]; then
echo "Error: Chart directory $chart_dir does not exist. Exiting fix the charts"
exit 1
fi

if [[ ! -f "$values_file" ]]; then
echo "Warning: Values file $values_file does not exist. Deploying without values."
values_file=""
fi

if [[ ! -f "$secrets_file" ]]; then
secrets_file=""
fi

helm_command="helm upgrade --install --wait --timeout=15m0s $chart $chart_dir"

if [[ -n "$values_file" ]]; then
helm_command+=" --values $values_file"
fi

if [[ -n "$secrets_file" ]]; then
helm_command+=" --values $secrets_file"
fi

# handle wire-server to inject PostgreSQL password from databases-ephemeral
if [[ "$chart" == "wire-server" ]]; then

echo "Retrieving PostgreSQL password from databases-ephemeral for wire-server deployment..."
if kubectl get secret wire-postgresql-secret &>/dev/null; then
# Usage: sync-k8s-secret-to-wire-secrets.sh <secret-name> <secret-key> <yaml-file> <yaml-path's>
"$BASE_DIR/bin/sync-k8s-secret-to-wire-secrets.sh" \
wire-postgresql-secret password \
"$BASE_DIR/values/wire-server/secrets.yaml" \
.brig.secrets.pgPassword .galley.secrets.pgPassword
else
echo "⚠️ Warning: PostgreSQL secret 'wire-postgresql-secret' not found, skipping secret sync"
echo " Make sure databases-ephemeral chart is deployed before wire-server"
fi
fi

echo "Deploying $chart as $helm_command"
eval "$helm_command"
done

# display running pods post deploying all helm charts in default namespace
kubectl get pods --sort-by=.metadata.creationTimestamp
}

deploy_cert_manager() {

kubectl get namespace cert-manager-ns || kubectl create namespace cert-manager-ns
helm upgrade --install -n cert-manager-ns cert-manager "$BASE_DIR/charts/cert-manager" --values "$BASE_DIR/values/cert-manager/values.yaml"

# display running pods
kubectl get pods --sort-by=.metadata.creationTimestamp -n cert-manager-ns
}

deploy_calling_services() {

echo "Deploying sftd and coturn"
# select the node to deploy sftd
kubectl annotate node "$CALLING_NODE" wire.com/external-ip="$HOST_IP" --overwrite
helm upgrade --install sftd "$BASE_DIR/charts/sftd" --set "nodeSelector.kubernetes\\.io/hostname=$CALLING_NODE" --values "$BASE_DIR/values/sftd/values.yaml"

kubectl annotate node "$CALLING_NODE" wire.com/external-ip="$HOST_IP" --overwrite
helm upgrade --install coturn "$BASE_DIR/charts/coturn" --set "nodeSelector.kubernetes\\.io/hostname=$CALLING_NODE" --values "$BASE_DIR/values/coturn/values.yaml" --values "$BASE_DIR/values/coturn/secrets.yaml"
}

main() {
# Create prod-values.example.yaml to values.yaml and take backup
process_values "prod" "values"
# Create prod-secrets.example.yaml to secrets.yaml and take backup
process_values "prod" "secrets"

# configure chart specific variables for each chart in values.yaml file
configure_values

# deploying with external datastores, useful for prod setup
deploy_charts cassandra-external elasticsearch-external minio-external postgresql-external fake-aws smtp rabbitmq databases-ephemeral reaper wire-server webapp account-pages team-settings smallstep-accomp ingress-nginx-controller

# deploying cert manager to issue certs, by default letsencrypt-http01 issuer is configured
deploy_cert_manager

# nginx-ingress-services chart needs cert-manager to be deployed
deploy_charts nginx-ingress-services

# deploying sft and coturn services
# not implemented yet
deploy_calling_services

# print status of certs
kubectl get certificate
}

main
5 changes: 2 additions & 3 deletions bin/offline-deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,10 @@ echo "Syncing PostgreSQL password from Kubernetes secret..."
sudo docker run --network=host -v $PWD:/wire-server-deploy $WSD_CONTAINER ./bin/sync-k8s-secret-to-wire-secrets.sh \
wire-postgresql-external-secret \
password \
values/wire-server/secrets.yaml \
values/wire-server/prod-secrets.example.yaml \
.brig.secrets.pgPassword \
.galley.secrets.pgPassword \
.spar.secrets.pgPassword \
.gundeck.secrets.pgPassword


sudo docker run --network=host -v $PWD:/wire-server-deploy $WSD_CONTAINER ./bin/offline-helm.sh
sudo docker run --network=host -v $PWD:/wire-server-deploy $WSD_CONTAINER ./bin/helm-operations.sh
16 changes: 11 additions & 5 deletions bin/offline-secrets.sh
Original file line number Diff line number Diff line change
Expand Up @@ -34,9 +34,9 @@ mls_ecdsa_p256_key="$(generate_mls_key -algorithm ec -pkeyopt ec_paramgen_curve:
mls_ecdsa_p384_key="$(generate_mls_key -algorithm ec -pkeyopt ec_paramgen_curve:P-384)"
mls_ecdsa_p521_key="$(generate_mls_key -algorithm ec -pkeyopt ec_paramgen_curve:P-521)"

if [[ ! -f $VALUES_DIR/wire-server/secrets.yaml ]]; then
echo "Writing $VALUES_DIR/wire-server/secrets.yaml"
cat <<EOF > $VALUES_DIR/wire-server/secrets.yaml

echo "Writing $VALUES_DIR/wire-server/prod-secrets.example.yaml"
cat <<EOF > $VALUES_DIR/wire-server/prod-secrets.example.yaml
brig:
secrets:
pgPassword: verysecurepassword
Expand Down Expand Up @@ -115,7 +115,13 @@ background-worker:
password: guest
EOF

fi
echo "Writing $VALUES_DIR/coturn/prod-secrets.example.yaml"
cat <<EOF > $VALUES_DIR/coturn/prod-secrets.example.yaml
secrets:
zrestSecrets:
- "$zrest"
EOF


if [[ ! -f $ANSIBLE_DIR/inventory/offline/group_vars/all/secrets.yaml ]]; then
echo "Writing $ANSIBLE_DIR/inventory/offline/group_vars/all/secrets.yaml"
Expand All @@ -127,7 +133,7 @@ minio_cargohold_secret_key: "$minio_cargohold_secret_key"
EOT
fi

PROM_AUTH_FILE="$VALUES_DIR/kube-prometheus-stack/secrets.yaml"
PROM_AUTH_FILE="$VALUES_DIR/kube-prometheus-stack/prod-secrets.example.yaml"
if [[ ! -f $PROM_AUTH_FILE ]]; then
echo "Writing $PROM_AUTH_FILE"
cat <<EOF > $PROM_AUTH_FILE
Expand Down
3 changes: 3 additions & 0 deletions changelog.d/3-deploy-builds/wpb-22439-helm-operations
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Added: bin/helm-operations.sh to replace offline-helm to be more closer to our production instrcutions
Changed: bin/offline-secrets.sh to support helm-operations.sh script and add support for coturn secret
Changed: reduce replica count for sftd and coturn to support wiab-staging
4 changes: 2 additions & 2 deletions values/coturn/prod-values.example.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# using upstream values for coturn helm
replicaCount: 3
replicaCount: 1
# image:
# tag: some-tag # (only override if you want a newer/different version than what is in the chart)
config:
Expand All @@ -10,7 +10,7 @@ config:
coturnTurnExternalIP: "__COTURN_EXT_IP__"
coturnTurnListenIP: "__COTURN_HOST_IP__"
coturnTurnRelayIP: "__COTURN_HOST_IP__"
coturnFederationListeningIP: "__COTURN_HOST_IP__"
#coturnFederationListeningIP: "__COTURN_HOST_IP__"
# Uncomment to enable federation
# federate:
# enabled: true
Expand Down
2 changes: 1 addition & 1 deletion values/sftd/prod-values.example.yaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
replicaCount: 3
replicaCount: 1
# image:
# tag: some-tag # (only override if you want a newer/different version than what is in the chart)
allowOrigin: https://webapp.example.com
Expand Down