Files
SODEW/sodew-bash-main/libs/commands/mariadb.sh
T
2026-08-18 09:40:08 +02:00

440 lines
16 KiB
Bash

mariadbLabel="[MariaDB]"
# Prepares Kubernetes secrets for MariaDB.
function cmdMariadbPreparation() {
printInfo "Preparation..."
local error
runError error k3sRun delete secret "$mariadbKube-secret" --ignore-not-found || {
printDotText "preparation" "$labelFail"
printDanger "Delete old Secret: $error"
return 1
}
runError error k3sRun create secret generic "$mariadbKube-secret" --from-literal=root-password="$mariadbRootPass" --from-literal=replication-password="$mariadbRootPass" || {
printDotText "preparation" "$labelFail"
printDanger "Create new Secret: $error"
return 1
}
printDotText "preparation" "$labelDone"
}
# Renders the MariaDB Kubernetes YAML manifest via Helm.
function cmdMariadbYamlRender() {
local templateFile="templates/$mariadbKube.yaml"
printSection "Render YAML file | Helm"
printDotText "Template" "$appAssetsPath/k3s/$templateFile"
[[ -f "$appAssetsPath/k3s/$templateFile" ]] || {
printDanger "Template file not found"
return 1
}
local profileCpuFile="$appAssetsPath/k3s/profiles/cpu-$kubeCpuProfile.yaml"
printDotText "CPU profile" "$profileCpuFile"
[[ -f "$profileCpuFile" ]] || {
printDanger "CPU profile file not found"
return 1
}
local profileMemoryFile="$appAssetsPath/k3s/profiles/memory-$kubeMemoryProfile.yaml"
printDotText "Memory profile" "$profileMemoryFile"
[[ -f "$profileMemoryFile" ]] || {
printDanger "Memory profile file not found"
return 1
}
local varsFile
varsFile=$(mktemp "/tmp/$mariadbKube.vars.XXXXXX.yaml") || {
printDotText "render" "$labelFail"
printDanger "Create temp variables file"
return 1
}
printDotText "Variables" "$varsFile"
trap 'rm -f -- "$varsFile"' RETURN
cat > "$varsFile" <<EOF
mariadbHelm: true
namespace: $k3sNamespace
mariadb: $mariadbKube
mariadbMaster: $mariadbMasterKube
mariadbSlave: $mariadbSlaveKube
mariadbMasterPath: $mariadbMasterPath
mariadbSlavePath: $mariadbSlavePath
EOF
printDotText "Result" "$mariadbYaml"
mkdir -p -- "$(dirname -- "$mariadbYaml")" || return 1
fileBackup "$mariadbYaml"
helm template stack "$appAssetsPath/k3s" -f "$varsFile" -f "$profileCpuFile" -f "$profileMemoryFile" --show-only "$templateFile" > "$mariadbYaml" || {
printDotText "render" "$labelFail"
printDanger "Render failed"
return 1
}
printDotText "render" "$labelDone"
}
# Waits until both MariaDB master and slave respond to SQL queries.
function cmdMariadbWaitMasterSlave() {
local error step attempts=15
for ((step=1; step<=attempts; step++)); do
runError error mariadbMasterRootQuery "SELECT 1;" && break
if [[ "$step" -ne "$attempts" ]]; then
printWarning "Master node | Waiting..."
sleep 4
else
printDanger "Master node | Not responding"
return 1
fi
done
for ((step=1; step<=attempts; step++)); do
runError error mariadbSlaveRootQuery "SELECT 1;" && break
if [[ "$step" -ne "$attempts" ]]; then
printWarning "Slave node | Waiting..."
sleep 4
else
printDanger "Slave node | Not responding"
return 1
fi
done
}
# Rebuilds MariaDB replication from master to slave.
# [$1] (masterPassword): replication password (defaults to $mariadbRootPass).
function cmdMariadbReplicaRebuild() {
local masterPassword="${1:-$mariadbRootPass}"
printInfo "Replica rebuild..."
local output error
runError error mariadbMasterRootQuery "SELECT 1;" || {
printDanger "Master node | Not responding: $error"
return 1
}
runError error mariadbSlaveRootQuery "SELECT 1;" || {
printDanger "Slave node | Not responding: $error"
return 1
}
runError error mariadbMasterRootQuery "CREATE USER IF NOT EXISTS 'replication_user'@'%' IDENTIFIED BY '$masterPassword'; GRANT REPLICATION SLAVE, REPLICATION CLIENT ON *.* TO 'replication_user'@'%'; ALTER USER 'replication_user'@'%' IDENTIFIED BY '$masterPassword';" || {
printDanger "Master node | Recreated replication user: $error"
return 1
}
printInfo "Master node | Recreated replication user"
local dumpFile="$appDataPath/$mariadbMasterKube/${appDate}_${appTime}_replica_rebuild.sql"
printInfo "Master node | Exporting full dump..."
mariadbMasterRootExport all "$dumpFile" || {
printDanger "Master node | Export failed"
return 1
}
printInfo "Master node | Exported: $dumpFile"
local masterFile masterPos
masterFile=$(grep -m1 -oE "MASTER_LOG_FILE='[^']+'" "$dumpFile" | sed "s/MASTER_LOG_FILE='//;s/'//")
masterPos=$(grep -m1 -oE "MASTER_LOG_POS=[0-9]+" "$dumpFile" | sed 's/MASTER_LOG_POS=//')
[[ -n "$masterFile" && -n "$masterPos" ]] || {
printDanger "Master node | Cannot parse MASTER_LOG_FILE/MASTER_LOG_POS from dump"
return 1
}
printInfo "Master node | Binlog: $masterFile:$masterPos"
printInfo "Slave node | Stopping replication..."
runError error mariadbSlaveRootQuery "STOP SLAVE; RESET SLAVE ALL;" || {
printDanger "Slave node | Stop/reset failed: $error"
return 1
}
printInfo "Slave node | Importing full dump..."
runShell output error k3sRun exec -i pod/"$mariadbSlaveKube"-0 -c "$mariadbSlaveKube" -- mariadb -u "root" -p"$mariadbRootPass" "<" "$dumpFile" ">" /dev/null || {
printDanger "Slave node | Import failed: ${error:-$output}"
return 1
}
printInfo "Slave node | Import completed"
runError error mariadbSlaveRootQuery "CHANGE MASTER TO MASTER_HOST='${mariadbMasterKube}', MASTER_PORT=3306, MASTER_USER='replication_user', MASTER_PASSWORD='${masterPassword}', MASTER_LOG_FILE='${masterFile}', MASTER_LOG_POS=${masterPos}; START SLAVE;" || {
printDanger "Slave node | Configure replication failed: $error"
return 1
}
printInfo "Slave node | Replication configured"
run output error mariadbSlaveRootQuery "SHOW SLAVE STATUS\G" showColumn || {
printDanger "Slave node | Status: $error"
return 1
}
local ioRunning sqlRunning secondsBehind lastError
ioRunning=$(printf '%s\n' "$output" | awk -F': ' '/^ *Slave_IO_Running:/{print $2}' | tr -d '[:space:]')
sqlRunning=$(printf '%s\n' "$output" | awk -F': ' '/^ *Slave_SQL_Running:/{print $2}' | tr -d '[:space:]')
secondsBehind=$(printf '%s\n' "$output" | awk -F': ' '/^ *Seconds_Behind_Master:/{print $2}' | tr -d '[:space:]')
lastError=$(printf '%s\n' "$output" | awk -F': ' '/^ *Last_Error:/{print substr($0, index($0,$2))}')
if [[ "$ioRunning" != "Yes" || "$sqlRunning" != "Yes" ]]; then
printWarning "Slave node | IO:${ioRunning:-?} | SQL:${sqlRunning:-?}"
[[ -n "$lastError" ]] && printWarning "Slave node | Last error: $lastError"
return 1
fi
printSuccess "Replica rebuild completed | Delay ${secondsBehind:-0}s"
}
# Updates MariaDB Kubernetes resources (limits, config, etc.) without re-initialization.
function cmdMariadbUpdate() {
cmdMariadbYamlRender || return 1
cmdK3sYamlApplyEx "$mariadbYaml" || return 1
}
# Installs MariaDB into Kubernetes and initializes replication.
function cmdMariadbInstall() {
cmdMariadbPreparation || return 1
cmdMariadbYamlRender || return 1
cmdK3sYamlApplyEx "$mariadbYaml" || return 1
cmdMariadbWaitMasterSlave || return 1
cmdMariadbReplicaRebuild || return 1
}
# Uninstalls MariaDB Kubernetes resources.
function cmdMariadbUninstall() {
"$k3sCmd" kubectl delete -f "$mariadbYaml"
}
# Checks MariaDB root password, replication health, database/user count, and total data size.
function cmdMariadbInfo() {
local password
password=$(mariadbRootPassSecretGet)
if [[ "$password" != "$mariadbRootPass" ]]; then
printRow
printDotText "Root password" "$labelFail"
printDanger "Use mariadbRootPassSecretSave"
return 1
fi
local podList output error pod ready phase reason
# Master
if ! run podList error k3sPodListStatus "$mariadbMasterKube"; then
printDanger "Get pods (master): $error"
elif [[ -z "$podList" ]]; then
printDanger "Pods (master) not found"
else
while IFS='|' read -r pod ready phase reason; do
printSection "$pod"
if [[ "$ready" != "1" ]]; then
printDotText "Status" "$fontGray$reason $fontYellow$phase$fontReset"
else
printDotText "Status" "$fontGreen$phase$fontReset"
if ! run output error mariadbMasterRootQuery "SELECT VERSION();"; then
printDotText "MariaDB status" "$fontRed$labelFail$fontReset"
printDanger "$error"
continue
fi
printDotText "MariaDB status" "$labelRunning"
printDotText "MariaDB version" "$output"
local masterStatus file position activeConnections
if ! run masterStatus error mariadbMasterRootQuery "SHOW MASTER STATUS\G;" "showColumn"; then
printDotText "Replica role" "$fontRed$labelUnknown$fontReset"
printDanger "$error"
continue
fi
file=$(printf '%s\n' "$masterStatus" | awk '/^ *File:/{print $2}')
if [[ -z "$file" ]]; then
printDotText "Replica role" "$fontRed$labelUnknown$fontReset"
printDanger "Params 'File' not found"
continue
fi
position=$(printf '%s\n' "$masterStatus" | awk '/^ *Position:/{print $2}')
if [[ -z "$position" ]]; then
printDotText "Replica role" "$fontRed$labelUnknown$fontReset"
printDanger "Params 'Position' not found"
continue
fi
if ! run output error mariadbMasterRootQuery "SHOW STATUS LIKE 'Threads_connected';"; then
printDotText "Replica role" "$fontRed$labelUnknown$fontReset"
printDanger "$error"
continue
fi
printDotText "Replica role" "${fontGreen}master$fontReset"
activeConnections=$(printf '%s\n' "$output" | awk '{print $2}')
if [[ "$activeConnections" -ge 100 || "$activeConnections" -eq 1 ]]; then
printDotText "Active connections" "$fontYellow$activeConnections$fontReset"
else
printDotText "Active connections" "$fontGreen$activeConnections$fontReset"
fi
fi
done < <(awk 'NF' <<< "$podList")
fi
# Slave
if ! run podList error k3sPodListStatus "$mariadbSlaveKube"; then
printDanger "Get pods (slave): $error"
elif [[ -z "$podList" ]]; then
printDanger "Pods (slave) not found"
else
while IFS='|' read -r pod ready phase reason; do
printSection "$pod"
if [[ "$ready" != "1" ]]; then
printDotText "Status" "$fontGray$reason $fontYellow$phase$fontReset"
else
printDotText "Status" "$fontGreen$phase$fontReset"
if ! run output error mariadbSlaveRootQuery "SELECT VERSION();"; then
printDotText "MariaDB status" "$fontRed$labelFail$fontReset"
printDanger "$error"
continue
fi
printDotText "MariaDB status" "$labelRunning"
printDotText "MariaDB version" "$output"
local slaveStatus slaveIoRunning slaveSqlRunning lastError secondsBehindMaster
if ! run slaveStatus error mariadbSlaveRootQuery "SHOW SLAVE STATUS\G;" "showColumn"; then
printDotText "Replica role" "$fontRed$labelUnknown$fontReset"
printDanger "$error"
continue
fi
slaveIoRunning=$(printf '%s\n' "$slaveStatus" | awk '/^ *Slave_IO_Running:/{print $2}')
if [[ "$slaveIoRunning" != "Yes" ]]; then
printDotText "Slave IO Running" "$fontRed$slaveIoRunning$fontReset"
continue
fi
slaveSqlRunning=$(printf '%s\n' "$slaveStatus" | awk '/^ *Slave_SQL_Running:/{print $2}')
if [[ "$slaveSqlRunning" != "Yes" ]]; then
printDotText "Slave SQL Running" "$fontRed$slaveSqlRunning$fontReset"
continue
fi
lastError=$(printf '%s\n' "$slaveStatus" | awk '/^ *Last_Error:/{$1=""; sub(/^[ \t]+/,""); print}')
if [[ -n "$lastError" ]]; then
printDotText "Slave SQL Running" "$fontRed$slaveSqlRunning$fontReset"
printDanger "Last error: $lastError"
continue
fi
printDotText "Replica role" "${fontGreen}slave$fontReset"
secondsBehindMaster=$(printf '%s\n' "$slaveStatus" | awk '/^ *Seconds_Behind_Master:/{print $2}')
if [[ "$secondsBehindMaster" -ne 0 ]]; then
printDotText "Replication lags" "$fontYellow${secondsBehindMaster}s$fontReset"
else
printDotText "Replication lags" "${fontGreen}0s$fontReset"
fi
fi
done < <(awk 'NF' <<< "$podList")
fi
printSection "MariaDB"
local databaseList userList dataSize
if run output error mariadbDatabaseListGet; then
mapfile -t databaseList < <(awk 'NF' <<< "$output")
printDotText "Databases" "${#databaseList[@]}"
else
printDotText "Databases" "$labelUnknown"
printDanger "$error"
fi
if run output error mariadbUserListGet; then
mapfile -t userList < <(awk 'NF' <<< "$output")
printDotText "Users" "${#userList[@]}"
else
printDotText "Users" "$labelUnknown"
printDanger "$error"
fi
if ! run dataSize error mariadbMasterRootQuery "SELECT ROUND(COALESCE(SUM(DATA_LENGTH + INDEX_LENGTH), 0) / 1024 / 1024 / 1024, 2) AS t FROM information_schema.TABLES WHERE TABLE_TYPE = 'BASE TABLE';"; then
printDotText "Size" "$labelUnknown"
printDanger "$error"
else
printDotText "Size" "$dataSize Gb"
fi
}
# Shows MariaDB master and slave replication status.
function cmdMariadbStatus() {
local output error
printSection "$mariadbMasterKube"-0
if ! run output error mariadbMasterRootQuery "SHOW MASTER STATUS;"; then
printDanger "$error"
else
printText "$output"
fi
printSection "$mariadbSlaveKube"-0
if ! run output error mariadbSlaveRootQuery "SHOW SLAVE STATUS\G;" showColumn; then
printDanger "$error"
else
printText "$output"
fi
}
# Lists all MariaDB databases.
function cmdMariadbDatabase() {
local output error
printRow
if ! run output error mariadbDatabaseListGet; then
printDanger "$error"
elif [[ -z "$output" ]]; then
printText "$labelNull"
else
printText "$output"
fi
}
# Lists all MariaDB users.
function cmdMariadbUser() {
local output error
printRow
if ! run output error mariadbUserListGet; then
printDanger "$error"
elif [[ -z "$output" ]]; then
printText "$labelNull"
else
printText "$output"
fi
}
# Exports a full dump from the MariaDB master node.
# [$@] (...): arguments passed to mariadbMasterRootExport (e.g. database name, file).
function cmdMariadbMasterDump() {
local output error
printRow
if ! run output error mariadbMasterRootExport "$@"; then
printDanger "$error"
else
printText "$output"
fi
}
# Exports a full dump from the MariaDB slave node.
# [$@] (...): arguments passed to mariadbSlaveRootExport (e.g. database name, file).
function cmdMariadbSlaveDump() {
local output error
printRow
if ! run output error mariadbSlaveRootExport "$@"; then
printDanger "$error"
else
printText "$output"
fi
}