forked from baron/baron-sso
웍스 드라이브 구조 변경
This commit is contained in:
185
scripts/docker-image/download_works_drive.sh
Executable file
185
scripts/docker-image/download_works_drive.sh
Executable file
@@ -0,0 +1,185 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
repo_root="$(cd "$script_dir/../.." && pwd)"
|
||||
source "$repo_root/scripts/backup/lib/common.sh"
|
||||
|
||||
dotenv_value() {
|
||||
local key="$1"
|
||||
local env_file="${WORKS_DOCKER_IMAGE_ENV_FILE:-.env}"
|
||||
|
||||
[[ -f "$env_file" ]] || return 0
|
||||
sed -n "s/^${key}=//p" "$env_file" | tail -n 1
|
||||
}
|
||||
|
||||
urlencode_path() {
|
||||
jq -nr --arg value "$1" '$value|@uri'
|
||||
}
|
||||
|
||||
split_curl_response() {
|
||||
local response="$1"
|
||||
local __body_var="$2"
|
||||
local __status_var="$3"
|
||||
local status
|
||||
local body
|
||||
|
||||
status="$(tail -n 1 <<<"$response")"
|
||||
if [[ "$status" =~ ^[0-9][0-9][0-9]$ ]]; then
|
||||
body="$(sed '$d' <<<"$response")"
|
||||
else
|
||||
status="200"
|
||||
body="$response"
|
||||
fi
|
||||
|
||||
printf -v "$__body_var" '%s' "$body"
|
||||
printf -v "$__status_var" '%s' "$status"
|
||||
}
|
||||
|
||||
redact_for_log() {
|
||||
sed -E 's/("(access_token|refresh_token|assertion|client_secret|Authorization)"[[:space:]]*:[[:space:]]*)"[^"]*"/\1"REDACTED"/Ig'
|
||||
}
|
||||
|
||||
resolve_files_endpoint() {
|
||||
local parent_file_id="${1:-}"
|
||||
local encoded_drive_id
|
||||
|
||||
encoded_drive_id="$(urlencode_path "$drive_id")"
|
||||
if [[ -n "$parent_file_id" ]]; then
|
||||
printf '%s/v1.0/sharedrives/%s/files/%s\n' "$api_base_url" "$encoded_drive_id" "$(urlencode_path "$parent_file_id")"
|
||||
else
|
||||
printf '%s/v1.0/sharedrives/%s/files\n' "$api_base_url" "$encoded_drive_id"
|
||||
fi
|
||||
}
|
||||
|
||||
list_children() {
|
||||
local parent_file_id="${1:-}"
|
||||
local endpoint
|
||||
local response
|
||||
local response_body
|
||||
local http_status
|
||||
|
||||
endpoint="$(resolve_files_endpoint "$parent_file_id")/children"
|
||||
response="$("$curl_bin" -sS -w $'\n%{http_code}' \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
"$endpoint")"
|
||||
split_curl_response "$response" response_body http_status
|
||||
|
||||
if [[ "$http_status" -lt 200 || "$http_status" -ge 300 ]]; then
|
||||
backup_die "WORKS folder list request failed (HTTP $http_status): $(printf '%s' "$response_body" | redact_for_log)"
|
||||
fi
|
||||
|
||||
printf '%s\n' "$response_body"
|
||||
}
|
||||
|
||||
find_child_id() {
|
||||
local parent_file_id="$1"
|
||||
local child_name="$2"
|
||||
local expected_type="${3:-}"
|
||||
local children_json
|
||||
|
||||
children_json="$(list_children "$parent_file_id")"
|
||||
jq -er --arg name "$child_name" --arg expectedType "$expected_type" '
|
||||
[
|
||||
(.files // .children // .items // [])[]
|
||||
| select((.fileName // .name) == $name)
|
||||
| select(
|
||||
$expectedType == ""
|
||||
or (((.fileType // .type // "") | ascii_downcase) == ($expectedType | ascii_downcase))
|
||||
)
|
||||
| .fileId // .id
|
||||
][0] // empty
|
||||
' <<<"$children_json" 2>/dev/null || true
|
||||
}
|
||||
|
||||
resolve_folder_path() {
|
||||
local path="$1"
|
||||
local parent_file_id="${WORKS_DRIVE_DOCKER_IMAGE_PARENT_FILE_ID:-}"
|
||||
local component
|
||||
local folder_id
|
||||
|
||||
IFS='/' read -r -a components <<<"$path"
|
||||
for component in "${components[@]}"; do
|
||||
[[ -n "$component" ]] || continue
|
||||
folder_id="$(find_child_id "$parent_file_id" "$component" "folder")"
|
||||
[[ -n "$folder_id" ]] || backup_die "WORKS Drive folder not found: ${path}"
|
||||
parent_file_id="$folder_id"
|
||||
done
|
||||
|
||||
printf '%s\n' "$parent_file_id"
|
||||
}
|
||||
|
||||
download_file() {
|
||||
local file_id="$1"
|
||||
local output_file="$2"
|
||||
local endpoint
|
||||
|
||||
endpoint="$(resolve_files_endpoint "$file_id")/download"
|
||||
"$curl_bin" -fL -sS \
|
||||
--location-trusted \
|
||||
-H "Authorization: Bearer $access_token" \
|
||||
-o "$output_file" \
|
||||
"$endpoint"
|
||||
}
|
||||
|
||||
load_image_archive() {
|
||||
local archive_file="$1"
|
||||
|
||||
backup_log "Loading Docker image archive: $(basename "$archive_file")"
|
||||
zstd -dc "$archive_file" | docker load >/dev/null
|
||||
}
|
||||
|
||||
image_tag="${IMAGE_TAG:-$(dotenv_value IMAGE_TAG)}"
|
||||
drive_id="${WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID:-${WORKS_DRIVE_SHARED_DRIVE_ID:-}}"
|
||||
access_token="${WORKS_DRIVE_ACCESS_TOKEN:-}"
|
||||
api_base_url="${WORKS_ADMIN_API_BASE_URL:-https://www.worksapis.com}"
|
||||
curl_bin="${WORKS_DRIVE_CURL_BIN:-curl}"
|
||||
image_root_dir="${WORKS_DRIVE_DOCKER_IMAGE_DIR:-${WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR:-baron-sso}}"
|
||||
download_root="${WORKS_DOCKER_IMAGE_DOWNLOAD_DIR:-/tmp/baron-sso-docker-image-download}"
|
||||
image_list="${WORKS_DOCKER_IMAGE_NAMES:-backend userfront adminfront devfront orgfront}"
|
||||
|
||||
[[ -n "$image_tag" ]] || backup_die "IMAGE_TAG is required."
|
||||
[[ -n "$drive_id" ]] || backup_die "WORKS_DRIVE_DOCKER_IMAGE_DRIVE_ID is required."
|
||||
[[ -n "$access_token" ]] || backup_die "WORKS_DRIVE_ACCESS_TOKEN is required."
|
||||
|
||||
backup_require_command jq
|
||||
backup_require_command sha256sum
|
||||
backup_require_command zstd
|
||||
backup_require_command docker
|
||||
backup_require_command "$curl_bin"
|
||||
|
||||
# Normalized remote path: baron-sso/${IMAGE_TAG}/${image}.${IMAGE_TAG}.tar.zst
|
||||
remote_path="${image_root_dir}/${image_tag}"
|
||||
target_folder_id="$(resolve_folder_path "$remote_path")"
|
||||
artifact_dir="${download_root}/${remote_path}"
|
||||
mkdir -p "$artifact_dir"
|
||||
|
||||
for image in $image_list; do
|
||||
archive_name="${image}.${image_tag}.tar.zst"
|
||||
checksum_name="${image}.${image_tag}.sha256"
|
||||
manifest_name="manifest.${image_tag}.json"
|
||||
|
||||
archive_id="$(find_child_id "$target_folder_id" "$archive_name")"
|
||||
checksum_id="$(find_child_id "$target_folder_id" "$checksum_name")"
|
||||
manifest_id="$(find_child_id "$target_folder_id" "$manifest_name")"
|
||||
|
||||
[[ -n "$archive_id" ]] || backup_die "WORKS Drive image archive not found: ${remote_path}/${archive_name}"
|
||||
[[ -n "$checksum_id" ]] || backup_die "WORKS Drive image checksum not found: ${remote_path}/${checksum_name}"
|
||||
[[ -n "$manifest_id" ]] || backup_die "WORKS Drive image manifest not found: ${remote_path}/${manifest_name}"
|
||||
|
||||
download_file "$archive_id" "$artifact_dir/$archive_name"
|
||||
download_file "$checksum_id" "$artifact_dir/$checksum_name"
|
||||
download_file "$manifest_id" "$artifact_dir/$manifest_name"
|
||||
|
||||
(
|
||||
cd "$artifact_dir"
|
||||
sha256sum -c "$checksum_name" >/dev/null
|
||||
)
|
||||
manifest_sha256="$(jq -er --arg image "$image" '.images[$image].archive.sha256 // .archive.sha256' "$artifact_dir/$manifest_name")"
|
||||
actual_sha256="$(sha256sum "$artifact_dir/$archive_name" | awk '{print $1}')"
|
||||
[[ "$manifest_sha256" == "$actual_sha256" ]] || backup_die "manifest sha256 mismatch for $archive_name"
|
||||
|
||||
load_image_archive "$artifact_dir/$archive_name"
|
||||
done
|
||||
|
||||
backup_log "Loaded WORKS Drive Docker image archives from ${remote_path}"
|
||||
@@ -68,7 +68,7 @@ image_ref="${DOCKER_IMAGE_REF:-${IMAGE_REF:-}}"
|
||||
|
||||
commit_container="${WORKS_DOCKER_COMMIT_CONTAINER:-${DOCKER_COMMIT_CONTAINER:-}}"
|
||||
archive_root="${WORKS_DOCKER_IMAGE_ARCHIVE_DIR:-/tmp/baron-sso-docker-image-upload}"
|
||||
image_root_dir="${WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR:-docker-build-image}"
|
||||
image_root_dir="${WORKS_DRIVE_DOCKER_IMAGE_DIR:-${WORKS_SHAREDRIVE_DOCKER_IMAGE_DIR:-baron-sso}}"
|
||||
dry_run="${WORKS_DRIVE_DRY_RUN:-false}"
|
||||
target="${WORKS_DRIVE_TARGET:-sharedrive}"
|
||||
api_base_url="${WORKS_ADMIN_API_BASE_URL:-https://www.worksapis.com}"
|
||||
@@ -504,14 +504,16 @@ derive_repository_and_tag() {
|
||||
|
||||
derive_repository_and_tag "$image_ref"
|
||||
|
||||
remote_path="${image_root_dir}/${image_repository}/${image_tag}"
|
||||
artifact_dir="${archive_root}/${image_repository}/${image_tag}"
|
||||
image_name="${image_repository##*/}"
|
||||
release_repository="${image_root_dir}"
|
||||
remote_path="${release_repository}/${image_tag}"
|
||||
artifact_dir="${archive_root}/${release_repository}/${image_tag}"
|
||||
mkdir -p "$artifact_dir"
|
||||
|
||||
tar_file="$artifact_dir/image.tar"
|
||||
archive_file="$artifact_dir/image.tar.zst"
|
||||
checksum_file="$artifact_dir/image.tar.zst.sha256"
|
||||
manifest_file="$artifact_dir/manifest.json"
|
||||
tar_file="$artifact_dir/${image_name}.${image_tag}.tar"
|
||||
archive_file="$artifact_dir/${image_name}.${image_tag}.tar.zst"
|
||||
checksum_file="$artifact_dir/${image_name}.${image_tag}.sha256"
|
||||
manifest_file="$artifact_dir/manifest.${image_tag}.json"
|
||||
upload_report_file="$artifact_dir/works-upload.json"
|
||||
|
||||
rm -f "$tar_file" "$archive_file" "$checksum_file" "$manifest_file" "$upload_report_file"
|
||||
@@ -535,36 +537,77 @@ image_id="$(docker image inspect "$image_ref" --format '{{.Id}}' 2>/dev/null ||
|
||||
archive_size="$(stat -c '%s' "$archive_file")"
|
||||
git_commit="$(backup_git_commit "$repo_root")"
|
||||
|
||||
jq -n \
|
||||
--arg createdAt "$(backup_utc_now)" \
|
||||
--arg imageRef "$image_ref" \
|
||||
--arg repository "$image_repository" \
|
||||
--arg tag "$image_tag" \
|
||||
--arg sourceContainer "$commit_container" \
|
||||
--arg imageId "$image_id" \
|
||||
--arg gitCommit "$git_commit" \
|
||||
--arg remotePath "$remote_path" \
|
||||
--arg archiveFile "$(basename "$archive_file")" \
|
||||
--arg archiveSha256 "$archive_sha256" \
|
||||
--argjson archiveSize "$archive_size" \
|
||||
'{
|
||||
schema_version: 1,
|
||||
format: "docker-save-zstd",
|
||||
created_at: $createdAt,
|
||||
manifest_tmp_file="${manifest_file}.tmp"
|
||||
manifest_jq_filter='
|
||||
def image_entry: {
|
||||
image_ref: $imageRef,
|
||||
repository: $repository,
|
||||
tag: $tag,
|
||||
image_name: $imageName,
|
||||
source_container: $sourceContainer,
|
||||
docker_image_id: $imageId,
|
||||
git_commit: $gitCommit,
|
||||
remote_path: $remotePath,
|
||||
restore_command: ("zstd -d -c " + $archiveFile + " | docker load"),
|
||||
archive: {
|
||||
file_name: $archiveFile,
|
||||
size_bytes: $archiveSize,
|
||||
sha256: $archiveSha256
|
||||
},
|
||||
restore_command: ("zstd -d -c " + $archiveFile + " | docker load")
|
||||
};
|
||||
.schema_version = 1
|
||||
| .format = "docker-save-zstd"
|
||||
| .created_at = (.created_at // $createdAt)
|
||||
| .updated_at = $createdAt
|
||||
| .image_ref = $imageRef
|
||||
| .repository = $repository
|
||||
| .release_repository = $releaseRepository
|
||||
| .image_name = $imageName
|
||||
| .tag = $tag
|
||||
| .source_container = $sourceContainer
|
||||
| .docker_image_id = $imageId
|
||||
| .git_commit = $gitCommit
|
||||
| .remote_path = $remotePath
|
||||
| .restore_command = ("zstd -d -c " + $archiveFile + " | docker load")
|
||||
| .archive = {
|
||||
file_name: $archiveFile,
|
||||
size_bytes: $archiveSize,
|
||||
sha256: $archiveSha256
|
||||
}
|
||||
}' >"$manifest_file"
|
||||
| .images = ((.images // {}) + {($imageName): image_entry})
|
||||
'
|
||||
|
||||
if [[ -f "$manifest_file" ]]; then
|
||||
jq \
|
||||
--arg createdAt "$(backup_utc_now)" \
|
||||
--arg imageRef "$image_ref" \
|
||||
--arg repository "$image_repository" \
|
||||
--arg releaseRepository "$release_repository" \
|
||||
--arg imageName "$image_name" \
|
||||
--arg tag "$image_tag" \
|
||||
--arg sourceContainer "$commit_container" \
|
||||
--arg imageId "$image_id" \
|
||||
--arg gitCommit "$git_commit" \
|
||||
--arg remotePath "$remote_path" \
|
||||
--arg archiveFile "$(basename "$archive_file")" \
|
||||
--arg archiveSha256 "$archive_sha256" \
|
||||
--argjson archiveSize "$archive_size" \
|
||||
"$manifest_jq_filter" "$manifest_file" >"$manifest_tmp_file"
|
||||
else
|
||||
jq -n \
|
||||
--arg createdAt "$(backup_utc_now)" \
|
||||
--arg imageRef "$image_ref" \
|
||||
--arg repository "$image_repository" \
|
||||
--arg releaseRepository "$release_repository" \
|
||||
--arg imageName "$image_name" \
|
||||
--arg tag "$image_tag" \
|
||||
--arg sourceContainer "$commit_container" \
|
||||
--arg imageId "$image_id" \
|
||||
--arg gitCommit "$git_commit" \
|
||||
--arg remotePath "$remote_path" \
|
||||
--arg archiveFile "$(basename "$archive_file")" \
|
||||
--arg archiveSha256 "$archive_sha256" \
|
||||
--argjson archiveSize "$archive_size" \
|
||||
"$manifest_jq_filter" >"$manifest_tmp_file"
|
||||
fi
|
||||
mv "$manifest_tmp_file" "$manifest_file"
|
||||
|
||||
upload_files=("$archive_file" "$checksum_file" "$manifest_file")
|
||||
|
||||
|
||||
@@ -17,6 +17,11 @@ backup_require_command stat
|
||||
backup_require_command zstd
|
||||
|
||||
manifest_file="$archive_dir/manifest.json"
|
||||
mapfile -t versioned_manifest_files < <(find "$archive_dir" -maxdepth 1 -type f -name 'manifest.*.json' | sort)
|
||||
if [[ "${#versioned_manifest_files[@]}" -gt 0 ]]; then
|
||||
[[ "${#versioned_manifest_files[@]}" -eq 1 ]] || backup_die "archive directory must contain exactly one manifest.*.json file."
|
||||
manifest_file="${versioned_manifest_files[0]}"
|
||||
fi
|
||||
backup_require_path "$manifest_file"
|
||||
|
||||
schema_version="$(jq -er '.schema_version' "$manifest_file")"
|
||||
@@ -33,6 +38,9 @@ manifest_size="$(jq -er '.archive.size_bytes' "$manifest_file")"
|
||||
|
||||
archive_file="$archive_dir/$archive_name"
|
||||
checksum_file="$archive_dir/${archive_name}.sha256"
|
||||
if [[ ! -f "$checksum_file" && "$archive_name" == *.tar.zst ]]; then
|
||||
checksum_file="$archive_dir/${archive_name%.tar.zst}.sha256"
|
||||
fi
|
||||
|
||||
backup_require_path "$archive_file"
|
||||
backup_require_path "$checksum_file"
|
||||
|
||||
Reference in New Issue
Block a user