forked from baron/baron-sso
백업/복구로직 변경, 깜빡임 버그 해결
This commit is contained in:
115
scripts/backup/lib/clickhouse.sh
Normal file
115
scripts/backup/lib/clickhouse.sh
Normal file
@@ -0,0 +1,115 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
clickhouse_query() {
|
||||
local container="$1"
|
||||
local user="$2"
|
||||
local password="$3"
|
||||
local query="$4"
|
||||
|
||||
docker exec "$container" clickhouse-client --user "$user" --password "$password" --query "$query"
|
||||
}
|
||||
|
||||
render_clickhouse_schema() {
|
||||
local schema_file="$1"
|
||||
|
||||
if head -n 1 "$schema_file" | grep -q '\\n'; then
|
||||
perl -0pe 's{\\n}{\n}g; s{\\t}{\t}g; s{\\\x27}{\x27}g' "$schema_file"
|
||||
return
|
||||
fi
|
||||
|
||||
cat "$schema_file"
|
||||
}
|
||||
|
||||
dump_clickhouse_container() {
|
||||
local backup_dir="$1"
|
||||
local service_name="$2"
|
||||
local container="$3"
|
||||
local user="$4"
|
||||
local password="$5"
|
||||
local output_dir="$backup_dir/clickhouse/$service_name"
|
||||
local table_list="$output_dir/tables.tsv"
|
||||
local database
|
||||
local table
|
||||
local engine
|
||||
local safe_name
|
||||
|
||||
backup_require_command docker
|
||||
backup_require_container "$container"
|
||||
mkdir -p "$output_dir/schema" "$output_dir/data" "$backup_dir/reports"
|
||||
|
||||
backup_log "Dumping ClickHouse metadata and Native data: $container"
|
||||
clickhouse_query "$container" "$user" "$password" \
|
||||
"select database, name, engine from system.tables where database not in ('INFORMATION_SCHEMA','information_schema','system') order by database, if(positionCaseInsensitive(engine, 'View') > 0, 1, 0), name format TSV" \
|
||||
>"$table_list"
|
||||
|
||||
while IFS=$'\t' read -r database table engine; do
|
||||
[[ -n "$database" && -n "$table" ]] || continue
|
||||
safe_name="${database}__${table}"
|
||||
clickhouse_query "$container" "$user" "$password" "show create table \`${database}\`.\`${table}\` FORMAT RawBLOB" >"$output_dir/schema/${safe_name}.sql"
|
||||
if [[ "$engine" != *View* ]]; then
|
||||
clickhouse_query "$container" "$user" "$password" "select * from \`${database}\`.\`${table}\` format Native" >"$output_dir/data/${safe_name}.native"
|
||||
fi
|
||||
clickhouse_query "$container" "$user" "$password" "select '${database}.${table}:' || toString(count()) from \`${database}\`.\`${table}\`" \
|
||||
>>"$backup_dir/reports/${service_name}-row-counts.txt"
|
||||
done <"$table_list"
|
||||
}
|
||||
|
||||
restore_clickhouse_container() {
|
||||
local backup_dir="$1"
|
||||
local service_name="$2"
|
||||
local container="$3"
|
||||
local user="$4"
|
||||
local password="$5"
|
||||
local input_dir="$backup_dir/clickhouse/$service_name"
|
||||
local table_list="$input_dir/tables.tsv"
|
||||
local database
|
||||
local table
|
||||
local engine
|
||||
local safe_name
|
||||
local restored_databases=""
|
||||
|
||||
backup_require_command docker
|
||||
backup_require_container "$container"
|
||||
backup_require_path "$table_list"
|
||||
|
||||
backup_log "Restoring ClickHouse tables: $container"
|
||||
while IFS=$'\t' read -r database table engine; do
|
||||
[[ -n "$database" && -n "$table" ]] || continue
|
||||
if ! grep -qw -- "$database" <<<"$restored_databases"; then
|
||||
docker exec "$container" clickhouse-client --user "$user" --password "$password" \
|
||||
--query "drop database if exists \`${database}\`"
|
||||
docker exec "$container" clickhouse-client --user "$user" --password "$password" \
|
||||
--query "create database if not exists \`${database}\`"
|
||||
restored_databases="${restored_databases:+$restored_databases }$database"
|
||||
fi
|
||||
done <"$table_list"
|
||||
|
||||
while IFS=$'\t' read -r database table engine; do
|
||||
[[ -n "$database" && -n "$table" ]] || continue
|
||||
safe_name="${database}__${table}"
|
||||
backup_require_path "$input_dir/schema/${safe_name}.sql"
|
||||
render_clickhouse_schema "$input_dir/schema/${safe_name}.sql" \
|
||||
| docker exec -i "$container" clickhouse-client --user "$user" --password "$password" --multiquery
|
||||
if [[ "$engine" != *View* ]]; then
|
||||
backup_require_path "$input_dir/data/${safe_name}.native"
|
||||
docker exec -i "$container" clickhouse-client --user "$user" --password "$password" \
|
||||
--query "insert into \`${database}\`.\`${table}\` format Native" <"$input_dir/data/${safe_name}.native"
|
||||
fi
|
||||
done <"$table_list"
|
||||
}
|
||||
|
||||
dump_baron_clickhouse() {
|
||||
dump_clickhouse_container "$1" "baron_clickhouse" "baron_clickhouse" "${CLICKHOUSE_USER:-baron}" "${CLICKHOUSE_PASSWORD:-password}"
|
||||
}
|
||||
|
||||
dump_ory_clickhouse() {
|
||||
dump_clickhouse_container "$1" "ory_clickhouse" "ory_clickhouse" "${ORY_CLICKHOUSE_USER:-ory}" "${ORY_CLICKHOUSE_PASSWORD:-orypass}"
|
||||
}
|
||||
|
||||
restore_baron_clickhouse() {
|
||||
restore_clickhouse_container "$1" "baron_clickhouse" "baron_clickhouse" "${CLICKHOUSE_USER:-baron}" "${CLICKHOUSE_PASSWORD:-password}"
|
||||
}
|
||||
|
||||
restore_ory_clickhouse() {
|
||||
restore_clickhouse_container "$1" "ory_clickhouse" "ory_clickhouse" "${ORY_CLICKHOUSE_USER:-ory}" "${ORY_CLICKHOUSE_PASSWORD:-orypass}"
|
||||
}
|
||||
137
scripts/backup/lib/common.sh
Normal file
137
scripts/backup/lib/common.sh
Normal file
@@ -0,0 +1,137 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
BACKUP_SUPPORTED_SERVICES="postgres ory-postgres clickhouse ory-clickhouse config"
|
||||
|
||||
backup_repo_root() {
|
||||
if [[ -n "${BACKUP_REPO_ROOT:-}" ]]; then
|
||||
printf '%s\n' "$BACKUP_REPO_ROOT"
|
||||
return
|
||||
fi
|
||||
|
||||
local script_dir
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../../.." && pwd)"
|
||||
printf '%s\n' "$script_dir"
|
||||
}
|
||||
|
||||
backup_log() {
|
||||
printf '==> %s\n' "$*"
|
||||
}
|
||||
|
||||
backup_die() {
|
||||
printf 'ERROR: %s\n' "$*" >&2
|
||||
return 1
|
||||
}
|
||||
|
||||
backup_require_command() {
|
||||
local command_name="$1"
|
||||
command -v "$command_name" >/dev/null 2>&1 || backup_die "required command not found: $command_name"
|
||||
}
|
||||
|
||||
backup_utc_now() {
|
||||
date -u '+%Y-%m-%dT%H:%M:%SZ'
|
||||
}
|
||||
|
||||
backup_timestamp() {
|
||||
date -u '+%Y%m%d-%H%M%SZ'
|
||||
}
|
||||
|
||||
backup_git_commit() {
|
||||
local repo_root="$1"
|
||||
git -c "safe.directory=$repo_root" -C "$repo_root" rev-parse --short=12 HEAD 2>/dev/null || printf 'unknown'
|
||||
}
|
||||
|
||||
normalize_service_filter() {
|
||||
local raw="${1:-all}"
|
||||
local normalized=""
|
||||
local candidate
|
||||
|
||||
if [[ "$raw" == "all" || -z "$raw" ]]; then
|
||||
printf '%s\n' "$BACKUP_SUPPORTED_SERVICES"
|
||||
return
|
||||
fi
|
||||
|
||||
raw="${raw//,/ }"
|
||||
for candidate in $raw; do
|
||||
if ! grep -qw -- "$candidate" <<<"$BACKUP_SUPPORTED_SERVICES"; then
|
||||
backup_die "unknown backup service: $candidate"
|
||||
return 1
|
||||
fi
|
||||
if ! grep -qw -- "$candidate" <<<"$normalized"; then
|
||||
normalized="${normalized:+$normalized }$candidate"
|
||||
fi
|
||||
done
|
||||
|
||||
[[ -n "$normalized" ]] || backup_die "service filter must not be empty"
|
||||
printf '%s\n' "$normalized"
|
||||
}
|
||||
|
||||
service_enabled() {
|
||||
local service="$1"
|
||||
local services="$2"
|
||||
local candidate
|
||||
|
||||
for candidate in $services; do
|
||||
[[ "$candidate" == "$service" ]] && return 0
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
backup_require_path() {
|
||||
local path="$1"
|
||||
[[ -e "$path" ]] || backup_die "required path not found: $path"
|
||||
}
|
||||
|
||||
backup_container_running() {
|
||||
local container="$1"
|
||||
docker inspect -f '{{.State.Running}}' "$container" 2>/dev/null | grep -qx 'true'
|
||||
}
|
||||
|
||||
backup_require_container() {
|
||||
local container="$1"
|
||||
backup_container_running "$container" || backup_die "container is not running: $container"
|
||||
}
|
||||
|
||||
backup_redact_env() {
|
||||
local source_file="$1"
|
||||
local target_file="$2"
|
||||
|
||||
sed -E '/^[[:space:]]*#/! s/^([^=]*(SECRET|PASSWORD|TOKEN|KEY|PRIVATE|CLIENT_SECRET|COOKIE)[^=]*)=.*/\1=REDACTED/I' "$source_file" >"$target_file"
|
||||
}
|
||||
|
||||
backup_checksum_file() {
|
||||
local backup_dir="$1"
|
||||
(
|
||||
cd "$backup_dir"
|
||||
find . -type f ! -name 'checksums.sha256' -print0 \
|
||||
| sort -z \
|
||||
| xargs -0 sha256sum
|
||||
) >"$backup_dir/checksums.sha256"
|
||||
}
|
||||
|
||||
backup_verify_checksums() {
|
||||
local backup_dir="$1"
|
||||
backup_require_path "$backup_dir/checksums.sha256"
|
||||
(
|
||||
cd "$backup_dir"
|
||||
sha256sum -c checksums.sha256
|
||||
)
|
||||
}
|
||||
|
||||
backup_safe_tar() {
|
||||
local source_path="$1"
|
||||
local target_base="$2"
|
||||
local source_parent
|
||||
local source_name
|
||||
|
||||
[[ -e "$source_path" ]] || return 0
|
||||
|
||||
source_parent="$(dirname "$source_path")"
|
||||
source_name="$(basename "$source_path")"
|
||||
|
||||
if command -v zstd >/dev/null 2>&1; then
|
||||
tar --zstd -cf "${target_base}.tar.zst" -C "$source_parent" "$source_name"
|
||||
else
|
||||
tar -czf "${target_base}.tar.gz" -C "$source_parent" "$source_name"
|
||||
fi
|
||||
}
|
||||
37
scripts/backup/lib/config.sh
Normal file
37
scripts/backup/lib/config.sh
Normal file
@@ -0,0 +1,37 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
dump_config_snapshot() {
|
||||
local backup_dir="$1"
|
||||
local repo_root
|
||||
|
||||
repo_root="$(backup_repo_root)"
|
||||
mkdir -p "$backup_dir/config"
|
||||
|
||||
if [[ -f "$repo_root/.env" ]]; then
|
||||
backup_redact_env "$repo_root/.env" "$backup_dir/config/env.redacted"
|
||||
fi
|
||||
|
||||
backup_safe_tar "$repo_root/config/.generated/ory" "$backup_dir/config/generated-ory"
|
||||
backup_safe_tar "$repo_root/gateway" "$backup_dir/config/gateway"
|
||||
|
||||
mkdir -p "$backup_dir/config/compose"
|
||||
for compose_file in compose.infra.yaml compose.ory.yaml docker-compose.yaml; do
|
||||
if [[ -f "$repo_root/$compose_file" ]]; then
|
||||
cp "$repo_root/$compose_file" "$backup_dir/config/compose/$compose_file"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
restore_config_snapshot() {
|
||||
local backup_dir="$1"
|
||||
local repo_root
|
||||
local output_dir
|
||||
|
||||
repo_root="$(backup_repo_root)"
|
||||
output_dir="$repo_root/config-restored"
|
||||
|
||||
backup_require_path "$backup_dir/config"
|
||||
mkdir -p "$output_dir"
|
||||
cp -R "$backup_dir/config/." "$output_dir/"
|
||||
backup_log "Config snapshot was copied to $output_dir for manual review."
|
||||
}
|
||||
42
scripts/backup/lib/manifest.sh
Normal file
42
scripts/backup/lib/manifest.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
create_manifest() {
|
||||
local backup_dir="$1"
|
||||
local mode="$2"
|
||||
local services="$3"
|
||||
local repo_root
|
||||
local created_at
|
||||
local git_commit
|
||||
local service
|
||||
local first=1
|
||||
|
||||
repo_root="$(backup_repo_root)"
|
||||
created_at="$(backup_utc_now)"
|
||||
git_commit="$(backup_git_commit "$repo_root")"
|
||||
|
||||
{
|
||||
printf '{\n'
|
||||
printf ' "format_version": "1",\n'
|
||||
printf ' "created_at": "%s",\n' "$created_at"
|
||||
printf ' "git_commit": "%s",\n' "$git_commit"
|
||||
printf ' "mode": "%s",\n' "$mode"
|
||||
printf ' "environment_scope": "same-env-only",\n'
|
||||
printf ' "services": ['
|
||||
for service in $services; do
|
||||
if [[ "$first" -eq 1 ]]; then
|
||||
first=0
|
||||
else
|
||||
printf ', '
|
||||
fi
|
||||
printf '"%s"' "$service"
|
||||
done
|
||||
printf '],\n'
|
||||
printf ' "restore_policy": {\n'
|
||||
printf ' "requires_empty_target": true,\n'
|
||||
printf ' "requires_confirmation": "baron-sso",\n'
|
||||
printf ' "auto_run_migrations": false,\n'
|
||||
printf ' "works_relay_auto_resume": false\n'
|
||||
printf ' }\n'
|
||||
printf '}\n'
|
||||
} >"$backup_dir/manifest.json"
|
||||
}
|
||||
95
scripts/backup/lib/postgres.sh
Normal file
95
scripts/backup/lib/postgres.sh
Normal file
@@ -0,0 +1,95 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
dump_baron_postgres() {
|
||||
local backup_dir="$1"
|
||||
local db_user="${DB_USER:-baron}"
|
||||
local db_password="${DB_PASSWORD:-password}"
|
||||
local db_name="${DB_NAME:-baron_sso}"
|
||||
|
||||
backup_require_command docker
|
||||
backup_require_container baron_postgres
|
||||
mkdir -p "$backup_dir/postgres" "$backup_dir/reports"
|
||||
|
||||
backup_log "Dumping Baron Postgres database: $db_name"
|
||||
docker exec -e "PGPASSWORD=$db_password" baron_postgres \
|
||||
pg_dump -U "$db_user" -d "$db_name" -Fc >"$backup_dir/postgres/baron.dump"
|
||||
|
||||
docker exec -e "PGPASSWORD=$db_password" baron_postgres \
|
||||
psql -U "$db_user" -d "$db_name" -Atc "select schemaname || '.' || relname || ':' || (xpath('/row/c/text()', query_to_xml(format('select count(*) as c from %I.%I', schemaname, relname), false, true, '')))[1]::text from pg_stat_user_tables order by 1" \
|
||||
>"$backup_dir/reports/baron-postgres-row-counts.txt"
|
||||
}
|
||||
|
||||
dump_ory_postgres() {
|
||||
local backup_dir="$1"
|
||||
local db_user="${ORY_POSTGRES_USER:-ory}"
|
||||
local db_password="${ORY_POSTGRES_PASSWORD:-secret}"
|
||||
local kratos_db="${KRATOS_DB:-ory_kratos}"
|
||||
local hydra_db="${HYDRA_DB:-ory_hydra}"
|
||||
local keto_db="${KETO_DB:-ory_keto}"
|
||||
local db_name
|
||||
|
||||
backup_require_command docker
|
||||
backup_require_container ory_postgres
|
||||
mkdir -p "$backup_dir/postgres" "$backup_dir/reports"
|
||||
|
||||
backup_log "Dumping Ory Postgres globals"
|
||||
docker exec -e "PGPASSWORD=$db_password" ory_postgres \
|
||||
pg_dumpall -U "$db_user" --globals-only >"$backup_dir/postgres/globals.sql"
|
||||
|
||||
for db_name in "$kratos_db" "$hydra_db" "$keto_db"; do
|
||||
backup_log "Dumping Ory Postgres database: $db_name"
|
||||
docker exec -e "PGPASSWORD=$db_password" ory_postgres \
|
||||
pg_dump -U "$db_user" -d "$db_name" -Fc >"$backup_dir/postgres/${db_name}.dump"
|
||||
docker exec -e "PGPASSWORD=$db_password" ory_postgres \
|
||||
psql -U "$db_user" -d "$db_name" -Atc "select schemaname || '.' || relname || ':' || (xpath('/row/c/text()', query_to_xml(format('select count(*) as c from %I.%I', schemaname, relname), false, true, '')))[1]::text from pg_stat_user_tables order by 1" \
|
||||
>"$backup_dir/reports/${db_name}-row-counts.txt"
|
||||
done
|
||||
}
|
||||
|
||||
restore_baron_postgres() {
|
||||
local backup_dir="$1"
|
||||
local db_user="${DB_USER:-baron}"
|
||||
local db_password="${DB_PASSWORD:-password}"
|
||||
local db_name="${DB_NAME:-baron_sso}"
|
||||
|
||||
backup_require_path "$backup_dir/postgres/baron.dump"
|
||||
backup_require_command docker
|
||||
backup_require_container baron_postgres
|
||||
|
||||
backup_log "Restoring Baron Postgres database: $db_name"
|
||||
docker exec -i -e "PGPASSWORD=$db_password" baron_postgres \
|
||||
pg_restore -U "$db_user" -d "$db_name" --clean --if-exists <"$backup_dir/postgres/baron.dump"
|
||||
}
|
||||
|
||||
restore_ory_postgres() {
|
||||
local backup_dir="$1"
|
||||
local db_user="${ORY_POSTGRES_USER:-ory}"
|
||||
local db_password="${ORY_POSTGRES_PASSWORD:-secret}"
|
||||
local kratos_db="${KRATOS_DB:-ory_kratos}"
|
||||
local hydra_db="${HYDRA_DB:-ory_hydra}"
|
||||
local keto_db="${KETO_DB:-ory_keto}"
|
||||
local db_name
|
||||
|
||||
backup_require_command docker
|
||||
backup_require_container ory_postgres
|
||||
|
||||
for db_name in "$kratos_db" "$hydra_db" "$keto_db"; do
|
||||
backup_require_path "$backup_dir/postgres/${db_name}.dump"
|
||||
backup_log "Restoring Ory Postgres database: $db_name"
|
||||
docker exec -i -e "PGPASSWORD=$db_password" ory_postgres \
|
||||
pg_restore -U "$db_user" -d "$db_name" --clean --if-exists <"$backup_dir/postgres/${db_name}.dump"
|
||||
done
|
||||
}
|
||||
|
||||
postgres_target_has_data() {
|
||||
local container="$1"
|
||||
local user="$2"
|
||||
local password="$3"
|
||||
local database="$4"
|
||||
|
||||
backup_require_command docker
|
||||
backup_require_container "$container"
|
||||
docker exec -e "PGPASSWORD=$password" "$container" \
|
||||
psql -U "$user" -d "$database" -Atc "select exists (select 1 from pg_tables where schemaname not in ('pg_catalog','information_schema') limit 1)" \
|
||||
2>/dev/null | grep -qx 't'
|
||||
}
|
||||
142
scripts/backup/lib/report.sh
Normal file
142
scripts/backup/lib/report.sh
Normal file
@@ -0,0 +1,142 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
report_count_from_file() {
|
||||
local file_path="$1"
|
||||
local key="$2"
|
||||
|
||||
if [[ ! -f "$file_path" ]]; then
|
||||
printf '0\n'
|
||||
return
|
||||
fi
|
||||
|
||||
awk -F: -v key="$key" '$1 == key {print $2; found=1; exit} END {if (!found) print "0"}' "$file_path"
|
||||
}
|
||||
|
||||
report_first_count() {
|
||||
local key="$1"
|
||||
shift
|
||||
|
||||
local file_path
|
||||
local count
|
||||
|
||||
for file_path in "$@"; do
|
||||
count="$(report_count_from_file "$file_path" "$key")"
|
||||
if [[ "$count" != "0" ]]; then
|
||||
printf '%s\n' "$count"
|
||||
return
|
||||
fi
|
||||
done
|
||||
|
||||
printf '0\n'
|
||||
}
|
||||
|
||||
write_backup_markdown_report() {
|
||||
local backup_dir="$1"
|
||||
local status="$2"
|
||||
local services="$3"
|
||||
local timings_json="${4:-[]}"
|
||||
local reports_dir="$backup_dir/reports"
|
||||
local output_file="$reports_dir/backup-report.md"
|
||||
local created_at
|
||||
local manifest_created_at="unknown"
|
||||
local git_commit="unknown"
|
||||
local users
|
||||
local tenants
|
||||
local relying_parties
|
||||
local hydra_clients
|
||||
local works_org_units
|
||||
local works_users
|
||||
local timings_table
|
||||
|
||||
mkdir -p "$reports_dir"
|
||||
created_at="$(backup_utc_now)"
|
||||
|
||||
if [[ -f "$backup_dir/manifest.json" ]]; then
|
||||
manifest_created_at="$(jq -r '.created_at // "unknown"' "$backup_dir/manifest.json")"
|
||||
git_commit="$(jq -r '.git_commit // "unknown"' "$backup_dir/manifest.json")"
|
||||
fi
|
||||
|
||||
users="$(report_first_count "public.users" "$reports_dir/baron-postgres-row-counts.txt")"
|
||||
tenants="$(report_first_count "public.tenants" "$reports_dir/baron-postgres-row-counts.txt")"
|
||||
relying_parties="$(report_first_count "public.relying_parties" "$reports_dir/baron-postgres-row-counts.txt")"
|
||||
hydra_clients="$(report_first_count "public.hydra_client" "$reports_dir/ory_hydra-row-counts.txt")"
|
||||
works_org_units="$(report_first_count "public.works_org_units" "$reports_dir/baron-postgres-row-counts.txt")"
|
||||
works_users="$(report_first_count "public.works_users" "$reports_dir/baron-postgres-row-counts.txt")"
|
||||
|
||||
timings_table="$(jq -r '
|
||||
if type != "array" or length == 0 then
|
||||
"| 없음 | 0 |"
|
||||
else
|
||||
.[] | "| \(.service) | \(.duration_seconds) |"
|
||||
end
|
||||
' <<<"$timings_json")"
|
||||
|
||||
{
|
||||
printf '# Baron SSO Backup Report\n\n'
|
||||
printf '| 항목 | 값 |\n'
|
||||
printf '| --- | --- |\n'
|
||||
printf '| 생성 시각 | %s |\n' "$created_at"
|
||||
printf '| 백업 시각 | %s |\n' "$manifest_created_at"
|
||||
printf '| 상태 | %s |\n' "$status"
|
||||
printf '| 백업 경로 | `%s` |\n' "$backup_dir"
|
||||
printf '| Git Commit | `%s` |\n' "$git_commit"
|
||||
printf '| 서비스 | `%s` |\n\n' "$services"
|
||||
printf '## 요약\n\n'
|
||||
printf '| 지표 | 값 |\n'
|
||||
printf '| --- | ---: |\n'
|
||||
printf '| 사용자 | %s |\n' "$users"
|
||||
printf '| 테넌트 | %s |\n' "$tenants"
|
||||
printf '| RP | %s |\n' "$relying_parties"
|
||||
printf '| Hydra Client | %s |\n' "$hydra_clients"
|
||||
printf '| WORKS 조직 | %s |\n' "$works_org_units"
|
||||
printf '| WORKS 사용자 | %s |\n\n' "$works_users"
|
||||
printf '## 서비스별 수행 시간\n\n'
|
||||
printf '| 서비스 | 초 |\n'
|
||||
printf '| --- | ---: |\n'
|
||||
printf '%s\n' "$timings_table"
|
||||
} >"$output_file"
|
||||
}
|
||||
|
||||
write_restore_markdown_report() {
|
||||
local restore_json="$1"
|
||||
local output_file
|
||||
|
||||
[[ -f "$restore_json" ]] || return 0
|
||||
output_file="${restore_json%.json}.md"
|
||||
|
||||
jq -r '
|
||||
def services: (.services // [] | join(", "));
|
||||
def verification_rows:
|
||||
(.verification.target_reports // []) as $reports
|
||||
| if ($reports | length) == 0 then
|
||||
"| 없음 | not_run | |"
|
||||
else
|
||||
$reports[]
|
||||
| "| \(.service) | \(.status) | \(.diff_file // "") |"
|
||||
end;
|
||||
"# Baron SSO Restore Report\n",
|
||||
"| 항목 | 값 |",
|
||||
"| --- | --- |",
|
||||
"| 시작 시각 | \(.started_at // "unknown") |",
|
||||
"| 종료 시각 | \(.finished_at // "unknown") |",
|
||||
"| 상태 | \(.status // "unknown") |",
|
||||
"| 메시지 | \(.message // "") |",
|
||||
"| 입력 유형 | \(.backup_source // "unknown") |",
|
||||
"| 백업 경로 | `\(.backup_dir // "")` |",
|
||||
"| Dump 파일 | `\(.dump_file // "")` |",
|
||||
"| 서비스 | `\(services)` |",
|
||||
"",
|
||||
"## 검증",
|
||||
"",
|
||||
"| 항목 | 상태 |",
|
||||
"| --- | --- |",
|
||||
"| Dump checksum | \(.verification.dump_checksum // "not_run") |",
|
||||
"| 대상 row count | \(.verification.target_row_counts // "not_run") |",
|
||||
"",
|
||||
"## 대상별 검증 결과",
|
||||
"",
|
||||
"| 서비스 | 상태 | Diff |",
|
||||
"| --- | --- | --- |",
|
||||
verification_rows
|
||||
' "$restore_json" >"$output_file"
|
||||
}
|
||||
Reference in New Issue
Block a user