set fallback := true export CLICKHOUSE_NAMESPACE := env("CLICKHOUSE_NAMESPACE", "clickhouse") export CLICKHOUSE_CHART_VERSION := env("CLICKHOUSE_CHART_VERSION", "0.25.3") export EXTERNAL_SECRETS_NAMESPACE := env("EXTERNAL_SECRETS_NAMESPACE", "external-secrets") [private] default: @just --list --unsorted --list-submodules # Add Helm repository add-helm-repo: helm repo add clickhouse-operator https://docs.altinity.com/clickhouse-operator/ helm repo update # Remove Helm repository remove-helm-repo: helm repo remove clickhouse-operator # Create ClickHouse namespace create-namespace: @kubectl get namespace ${CLICKHOUSE_NAMESPACE} &>/dev/null || \ kubectl create namespace ${CLICKHOUSE_NAMESPACE} # Delete ClickHouse namespace delete-namespace: @kubectl delete namespace ${CLICKHOUSE_NAMESPACE} --ignore-not-found # Create ClickHouse credentials secret create-credentials: #!/bin/bash set -euo pipefail echo "Setting up ClickHouse credentials..." # Generate admin password ADMIN_PASSWORD=$(just utils::random-password) if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then echo "External Secrets available. Storing credentials in Vault and creating ExternalSecret..." just vault::put clickhouse/credentials admin="$ADMIN_PASSWORD" gomplate -f clickhouse-credentials-external-secret.gomplate.yaml -o clickhouse-credentials-external-secret.yaml kubectl apply -f clickhouse-credentials-external-secret.yaml echo "Waiting for credentials secret to be ready..." kubectl wait --for=condition=Ready externalsecret/clickhouse-credentials-external-secret \ -n ${CLICKHOUSE_NAMESPACE} --timeout=60s else echo "External Secrets not available. Creating Kubernetes Secret directly..." kubectl delete secret clickhouse-credentials -n ${CLICKHOUSE_NAMESPACE} --ignore-not-found kubectl create secret generic clickhouse-credentials -n ${CLICKHOUSE_NAMESPACE} \ --from-literal=admin="$ADMIN_PASSWORD" echo "Credentials secret created directly in Kubernetes" fi echo "ClickHouse credentials setup completed" # Delete ClickHouse credentials secret delete-credentials-secret: @kubectl delete secret clickhouse-credentials -n ${CLICKHOUSE_NAMESPACE} --ignore-not-found @kubectl delete externalsecret clickhouse-credentials-external-secret -n ${CLICKHOUSE_NAMESPACE} --ignore-not-found # Install ClickHouse install: just create-namespace just install-zookeeper just create-credentials just add-helm-repo helm upgrade --install clickhouse-operator clickhouse-operator/altinity-clickhouse-operator \ --version ${CLICKHOUSE_CHART_VERSION} -n ${CLICKHOUSE_NAMESPACE} --wait kubectl apply -n ${CLICKHOUSE_NAMESPACE} -f ./clickhouse.yaml echo "Waiting for ClickHouse installation to be ready..." kubectl wait --for=jsonpath='{.status.status}'=Completed \ clickhouseinstallation/clickhouse -n ${CLICKHOUSE_NAMESPACE} --timeout=600s echo "ClickHouse installation completed successfully" # Uninstall ClickHouse uninstall: #!/bin/bash set -euo pipefail echo "Uninstalling ClickHouse..." if kubectl get clickhouseinstallations.clickhouse.altinity.com \ -n ${CLICKHOUSE_NAMESPACE} &>/dev/null; then echo "Deleting ClickHouseInstallation resources..." kubectl delete clickhouseinstallations.clickhouse.altinity.com --all \ -n ${CLICKHOUSE_NAMESPACE} --timeout=30s --ignore-not-found || { echo "Graceful deletion timed out, forcing finalizer removal..." for chi in $(kubectl get clickhouseinstallations.clickhouse.altinity.com \ -n ${CLICKHOUSE_NAMESPACE} -o name 2>/dev/null); do kubectl patch "$chi" -n ${CLICKHOUSE_NAMESPACE} \ --type='merge' -p='{"metadata":{"finalizers":null}}' || true done } fi helm uninstall clickhouse-operator -n ${CLICKHOUSE_NAMESPACE} --wait --ignore-not-found just uninstall-zookeeper just delete-credentials-secret just delete-namespace echo "ClickHouse uninstalled successfully" # Print ClickHouse admin password admin-password: #!/bin/bash set -euo pipefail if helm status external-secrets -n ${EXTERNAL_SECRETS_NAMESPACE} &>/dev/null; then echo "Getting password from Vault..." just vault::get clickhouse/credentials admin else echo "Getting password from Kubernetes Secret..." kubectl get secret clickhouse-credentials -n ${CLICKHOUSE_NAMESPACE} \ -o jsonpath='{.data.admin}' | base64 -d echo fi # Connect to ClickHouse as admin connect-admin: check-env @just utils::check-connection clickhouse-clickhouse.clickhouse 9000 @clickhouse client --host clickhouse-clickhouse.clickhouse --port 9000 \ --user admin --password $(just clickhouse::admin-password) # Connect to ClickHouse connect user: check-env @just utils::check-connection clickhouse-clickhouse.clickhouse 9000 @clickhouse client --host clickhouse-clickhouse.clickhouse --port 9000 \ --user {{ user }} --ask-password # Create ClickHouse user create-user username='' password='': #!/bin/bash set -euo pipefail USERNAME=${USERNAME:-"{{ username }}"} PASSWORD=${PASSWORD:-"{{ password }}"} while [ -z "${USERNAME}" ]; do USERNAME=$(gum input --prompt="Username: " --width=100) done if just user-exists ${USERNAME} &>/dev/null; then echo "User ${USERNAME} already exists" >&2 exit fi if [ -z "${PASSWORD}" ]; then PASSWORD=$(gum input --prompt="Password: " --password --width=100 \ --placeholder="Empty to generate a random password") fi if [ -z "${PASSWORD}" ]; then PASSWORD=$(just utils::random-password) echo "Generated random password: ${PASSWORD}" fi echo "Creating ClickHouse user '${USERNAME}'..." just connect-admin </dev/null; then echo "User ${USERNAME} does not exist." >&2 exit fi echo "Deleting ClickHouse user '${USERNAME}'..." just connect-admin <&2 exit 1 fi if ! just user-exists ${USERNAME}; then echo "User ${USERNAME} does not exist." >&2 exit 1 fi echo "Granting all privileges on '${DB_NAME}' to ClickHouse user '${USERNAME}'..." just connect-admin <&2 exit 1 fi if ! just user-exists ${USERNAME}; then echo "User ${USERNAME} does not exist." >&2 exit 1 fi echo "Revoking all privileges on '${DB_NAME}' from ClickHouse user '${USERNAME}'..." just connect-admin </dev/null; then if just user-exists ${USERNAME} &>/dev/null; then just revoke "${DB_NAME}" "${USERNAME}" else echo "User ${USERNAME} does not exist, skipping revoke." fi just delete-db "${DB_NAME}" else echo "Database ${DB_NAME} does not exist, skipping database deletion." fi if just user-exists ${USERNAME} &>/dev/null; then just delete-user "${USERNAME}" else echo "User ${USERNAME} does not exist, skipping user deletion." fi echo "Cleanup completed." # List all users in ClickHouse list-users: #!/bin/bash set -euo pipefail just connect-admin </dev/null; then kubectl create namespace zookeeper fi kubectl apply -n ${CLICKHOUSE_NAMESPACE} -f ./zookeeper.yaml # Uninstall ZooKeeper uninstall-zookeeper: kubectl delete -n ${CLICKHOUSE_NAMESPACE} -f ./zookeeper.yaml # Clean up ClickHouse resources cleanup: #!/bin/bash set -euo pipefail echo "This will delete all ClickHouse resources and secrets." if gum confirm "Are you sure you want to proceed?"; then echo "Cleaning up ClickHouse resources..." just vault::delete clickhouse/credentials || true echo "Cleanup completed" else echo "Cleanup cancelled" fi # Check the environment [private] check-env: #!/bin/bash set -euo pipefail if ! command -v clickhouse &>/dev/null; then echo "clickhouse CLI is not installed. Please install it first." exit 1 fi