Compare commits

...
10 Commits
Author SHA1 Message Date
thuanleandClaude 3dbed651e5 Arch pkg cache: remove partial download-* files before pacman -Sc
pacman -Sc errors with 'could not open file .../download-XXXX: Error
reading fd 7' on leftover incomplete downloads. Find and remove them
(with confirm) first, then run paccache/pacman -Sc cleanly.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:45:17 +07:00
thuanleandClaude 171e5dc9c0 Show target host in every step header
Each step now prints "--- [Label] on <host> ---". The host is threaded
through the remote self-bootstrap as argv[2] so it shows the real
server name when running over ssh.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:36:56 +07:00
thuanleandClaude 2e126a1743 Fix target alias: aws -> aws-vanhoa (matches ~/.ssh/config)
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:35:22 +07:00
thuanleandClaude b64303bb23 Use legible figlet block-art banner (CLEANUP SERVER) with per-line rainbow
Replaces the gradient-bar version with proper figlet-style ASCII art
so the title is actually readable; each line colored in a rainbow
gradient, with a Vietnamese subtitle.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:26:25 +07:00
thuanleandClaude ab9d62fac6 Replace illegible box-art banner with readable gradient-bar banner
The Unicode box-drawing art didn't form legible letters. Now uses
two rainbow gradient bars around a plain, readable title + subtitle.

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:24:06 +07:00
thuanleandClaude ce49f1ce5c Harden step_snap: dedupe Set ids (multi-snap sets)
Local flow verified end-to-end (macOS guards). Remote Ubuntu/Arch
verification deferred to user (interactive, destructive on real hosts).

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:20:20 +07:00
thuanleandClaude a49f26adc8 Add step_tmp_cache: find >7d dry-run + confirmed rm
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:18:45 +07:00
thuanleandClaude f50579efb2 Add step_snap: list saved + forget per id
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:18:14 +07:00
thuanleandClaude 37ce7f6ca8 Add step_pkg_cache: apt clean / paccache / pacman -Sc
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:17:56 +07:00
thuanleandClaude f4c8f6c9e5 Add step_journal: disk-usage + vacuum-time=7d
Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-22 00:17:38 +07:00
+162 -22
View File
@@ -18,39 +18,47 @@ else
fi fi
# ----------------------------- # -----------------------------
# Banner rainbow (giống style `cleanup`) # Banner rainbow (ASCII art figlet, per-line gradient)
# ----------------------------- # -----------------------------
print_banner() { print_banner() {
local use_color=0 reset="" i=0 line
local -a lines=( local -a lines=(
' ██████╗██╗ ██╗ ██████╗██╗ ██╗██╗ ██╗██████╗ ███████╗███╗ ██╗ ██████╗██╗ ██╗' '▗▄▄▄▖▗▖ ▗▄▄▖▗▄▄▄▖▗▄▄▖ ▗▖ ▗▖▗▄▄▄▖▗▄▄▖ ▗▄▄▖▗▖ ▗▄▄▄▖ ▗▄▖ ▗▖ ▗▖▗▄▄▄▖▗▄▖ '
' ██╔════╝██║ ██║██╔════╝██║ ██║██║ ██║██╔══██╗ ██╔════╝████╗ ██║██╔═══██╗╚██╗██╔╝' ' █ ▐▌ ▐▌ ▐▌ ▐▌ ▐▌▐▌ ▐▌▐▌ ▐▌ ▐▌ ▐▌ ▐▌ ▐▌ ▐▌ ▐▌▐▛▚▖▐▌▐▌ ▐▌ ▐▌'
' ██║ ██║ ██║██║ ███████║██║ ██║██║ ██║ █████╗ ██╔██╗ ██║██║ ██║ ╚███╔╝ ' ' █ ▐▌ ▝▀▚▖▐▛▀▀▘▐▛▀▚▖▐▌ ▐▌▐▛▀▀▘▐▛▀▚▖ ▐▌ ▐▌ ▐▛▀▀▘▐▛▀▜▌▐▌ ▝▜▌▐▛▀▀▘▐▛▀▚▖'
' ██║ ██║ ██║██║ ██╔══██║██║ ██║██║ ██║ ██╔══╝ ██║╚██╗██║██║ ██║ ██╔██╗ ' ' █ ▐▙▄▄▖ ▗▄▄▞▘▐▙▄▄▖▐▌ ▐▌ ▝▚▞▘ ▐▙▄▄▖▐▌ ▐▌ ▝▚▄▄▖▐▙▄▄▖▐▙▄▄▖▐▌ ▐▌▐▌ ▐▌▐▙▄▄▖▐▌ ▐▌'
' ╚██████╗╚██████╔╝╚██████╗██║ ██║╚██████╔╝██████╔╝ ███████╗██║ ╚████║╚██████╔╝██╔╝ ██╗'
' ╚═════╝ ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═════╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝ ╚═════╝ ╚═╝ ╚═╝'
) )
local -a colors=() local -a colors=()
if [ -t 1 ]; then if [ -t 1 ]; then
use_color=1
reset=$'\033[0m'
colors=( colors=(
$'\033[1;38;5;51m' $'\033[1;38;5;87m' $'\033[1;38;5;123m' $'\033[1;38;5;51m' # cyan
$'\033[1;38;5;159m' $'\033[1;38;5;220m' $'\033[1;38;5;214m' $'\033[1;38;5;120m' # xanh lá
$'\033[1;38;5;220m' # vàng gold
$'\033[1;38;5;209m' # cam-đỏ
) )
fi fi
echo "" echo ""
for line in "${lines[@]}"; do local i
if [ "$use_color" -eq 1 ]; then for ((i = 0; i < ${#lines[@]}; i++)); do
printf '%b%s%b\n' "${colors[$i]}" "$line" "$reset" if [ -t 1 ]; then
printf '%s%s%s\n' "${colors[$i]}" "${lines[$i]}" "$C_RESET"
else else
printf '%s\n' "$line" printf '%s\n' "${lines[$i]}"
fi fi
i=$((i + 1))
done done
printf ' %sDọn dẹp + nâng cấp server (Ubuntu / Arch)%s\n' "$C_WARN" "$C_RESET"
echo "" echo ""
} }
# -----------------------------
# Host đang chạy (đặt ở main; hiển thị lại trong mỗi header bước)
# -----------------------------
CURRENT_TARGET="local"
# In header bước kèm host: --- [Label] on <host> ---
step_header() {
echo "${C_TITLE}--- [$1] on ${CURRENT_TARGET} ---${C_RESET}"
}
# ----------------------------- # -----------------------------
# Phát hiện distro qua /etc/os-release → debian | arch | unknown # Phát hiện distro qua /etc/os-release → debian | arch | unknown
# ----------------------------- # -----------------------------
@@ -83,7 +91,7 @@ confirm_yn() {
# ----------------------------- # -----------------------------
# Danh sách target fix cứng (alias từ ~/.ssh/config) # Danh sách target fix cứng (alias từ ~/.ssh/config)
# ----------------------------- # -----------------------------
TARGETS=("local" "ta" "toc" "oc" "cse" "vrc" "aws" "tk" "od") TARGETS=("local" "ta" "toc" "oc" "cse" "vrc" "aws-vanhoa" "tk" "od")
TARGET_CURSOR=0 TARGET_CURSOR=0
TARGET="" TARGET=""
@@ -131,7 +139,7 @@ select_target() {
# Bước 1: Nâng cấp hệ thống theo distro # Bước 1: Nâng cấp hệ thống theo distro
# ----------------------------- # -----------------------------
step_upgrade() { step_upgrade() {
echo "${C_TITLE}--- [System Upgrade] ---${C_RESET}" step_header "System Upgrade"
local distro local distro
distro=$(detect_distro) distro=$(detect_distro)
case "$distro" in case "$distro" in
@@ -184,7 +192,7 @@ docker_cmd() {
# Bước 2: Docker — df rồi prune từng loại # Bước 2: Docker — df rồi prune từng loại
# ----------------------------- # -----------------------------
step_docker() { step_docker() {
echo "${C_TITLE}--- [Docker] ---${C_RESET}" step_header "Docker"
if ! command -v docker >/dev/null 2>&1; then if ! command -v docker >/dev/null 2>&1; then
echo "${C_WARN} ⚠ docker command not found.${C_RESET}" echo "${C_WARN} ⚠ docker command not found.${C_RESET}"
echo "" echo ""
@@ -209,12 +217,141 @@ step_docker() {
echo "" echo ""
} }
# -----------------------------
# Bước 3: Journal logs — vacuum log cũ hơn 7 ngày
# -----------------------------
step_journal() {
step_header "Journal Logs"
if ! command -v journalctl >/dev/null 2>&1; then
echo "${C_WARN} ⚠ journalctl not found.${C_RESET}"
echo ""
return
fi
sudo journalctl --disk-usage
if confirm_yn "Vacuum log cũ hơn 7 ngày (--vacuum-time=7d)?"; then
sudo journalctl --vacuum-time=7d
echo "${C_OK} ✓ Đã dọn journal.${C_RESET}"
fi
echo ""
}
# -----------------------------
# Bước 4: Package cache — apt clean+autoremove hoặc paccache/pacman -Sc
# -----------------------------
step_pkg_cache() {
step_header "Package Cache"
local distro
distro=$(detect_distro)
case "$distro" in
debian)
local d="/var/cache/apt/archives"
[ -d "$d" ] && sudo du -sh "$d"
if confirm_yn "apt clean + autoremove?"; then
sudo apt-get clean
sudo apt-get autoremove -y
echo "${C_OK} ✓ Đã dọn apt cache.${C_RESET}"
fi
;;
arch)
local d="/var/cache/pacman/pkg"
[ -d "$d" ] && sudo du -sh "$d"
# Xóa file download tạm (incomplete) — pacman -Sc báo lỗi fd 7 với chúng.
local partial pcount
partial=$(sudo find "$d" -maxdepth 1 -type f -name 'download-*' 2>/dev/null)
if [ -n "$partial" ]; then
pcount=$(printf '%s\n' "$partial" | grep -c .)
echo " ${C_WARN}✗ ${pcount} file download tạm (incomplete).${C_RESET}"
if confirm_yn "Xóa file download-* tạm?"; then
printf '%s\n' "$partial" | xargs sudo rm -f --
echo "${C_OK} ✓ Đã xóa file tạm.${C_RESET}"
fi
fi
if command -v paccache >/dev/null 2>&1; then
sudo paccache -dk2 # dry-run xem trước
if confirm_yn "paccache -rk2 (giữ 2 bản)?"; then
sudo paccache -rk2
echo "${C_OK} ✓ Đã dọn pacman cache.${C_RESET}"
fi
else
if confirm_yn "Không có paccache, chạy pacman -Sc?"; then
sudo pacman -Sc --noconfirm
echo "${C_OK} ✓ Đã dọn pacman cache.${C_RESET}"
fi
fi
;;
*)
echo "${C_WARN} ⚠ Distro không hỗ trợ dọn package cache.${C_RESET}"
;;
esac
echo ""
}
# -----------------------------
# Bước 5: Snap — forget từng snapshot
# -----------------------------
step_snap() {
step_header "Snap"
if ! command -v snap >/dev/null 2>&1; then
echo "${C_WARN} ⚠ snap not found.${C_RESET}"
echo ""
return
fi
local saved
# Cột đầu (Set) là id cần forget; một Set có thể có nhiều Snap → dedupe.
saved=$(sudo snap saved 2>/dev/null | awk 'NR>1{print $1}' | awk '!seen[$0]++')
if [ -z "$saved" ]; then
echo "${C_OK} ✓ Không có snap snapshot nào.${C_RESET}"
echo ""
return
fi
local id
for id in $saved; do
if confirm_yn "Forget snap snapshot (Set $id)?"; then
sudo snap forget "$id"
fi
done
echo "${C_OK} ✓ Snap cleanup xong.${C_RESET}"
echo ""
}
# -----------------------------
# Bước 6: /tmp & cache cũ — liệt kê file >7 ngày, xác nhận rồi xóa
# -----------------------------
step_tmp_cache() {
step_header "/tmp & Cache cũ"
local days=7
echo " Tìm file cũ hơn ${days} ngày trong /tmp /var/tmp:"
local old_files
old_files=$(sudo find /tmp /var/tmp -type f -mtime +"$days" 2>/dev/null)
if [ -z "$old_files" ]; then
echo "${C_OK} ✓ Không có file cũ >${days} ngày.${C_RESET}"
echo ""
return
fi
local count total_kb total_mib
count=$(printf '%s\n' "$old_files" | grep -c .)
total_kb=$(printf '%s\n' "$old_files" | xargs sudo du -ck 2>/dev/null | tail -1 | cut -f1)
total_mib=$(( total_kb / 1024 ))
echo "${C_DEL} ✗ ${count} file, ~${total_mib} MiB.${C_RESET}"
printf '%s\n' "$old_files" | head -20 | sed 's/^/ - /'
[ "$count" -gt 20 ] && echo " ... (và $((count - 20)) file nữa)"
if confirm_yn "Xóa các file cũ >${days} ngày?"; then
printf '%s\n' "$old_files" | xargs sudo rm -f --
echo "${C_OK} ✓ Đã xóa.${C_RESET}"
fi
echo ""
}
# ----------------------------- # -----------------------------
# Chạy tuần tự 6 bước (stub — các bước thêm ở Task 4-9) # Chạy tuần tự 6 bước (stub — các bước thêm ở Task 4-9)
# ----------------------------- # -----------------------------
run_all_steps() { run_all_steps() {
step_upgrade step_upgrade
step_docker step_docker
step_journal
step_pkg_cache
step_snap
step_tmp_cache
} }
# ----------------------------- # -----------------------------
@@ -226,6 +363,7 @@ run_all_steps() {
run_on_target() { run_on_target() {
local target="$1" local target="$1"
if [ "$target" = "local" ]; then if [ "$target" = "local" ]; then
CURRENT_TARGET="local"
run_all_steps run_all_steps
return $? return $?
fi fi
@@ -235,8 +373,9 @@ run_on_target() {
return 1 return 1
} }
# Giải mã ra file tạm trên remote rồi chạy; stdin không bị redirect → read OK. # Giải mã ra file tạm trên remote rồi chạy; stdin không bị redirect → read OK.
# Truyền target làm argv[2] để remote biết host (hiển thị lại trong header).
ssh -t "$target" \ ssh -t "$target" \
"umask 077; t=\$(mktemp); printf '%s' '$b64' | base64 -d > \"\$t\" && bash \"\$t\" --run-steps; r=\$?; rm -f \"\$t\"; exit \$r" \ "umask 077; t=\$(mktemp); printf '%s' '$b64' | base64 -d > \"\$t\" && bash \"\$t\" --run-steps \"$target\"; r=\$?; rm -f \"\$t\"; exit \$r" \
|| { echo "${C_DEL} ✗ ssh tới $target thất bại.${C_RESET}"; return 1; } || { echo "${C_DEL} ✗ ssh tới $target thất bại.${C_RESET}"; return 1; }
} }
@@ -245,7 +384,8 @@ run_on_target() {
# ----------------------------- # -----------------------------
main() { main() {
if [ "${1:-}" = "--run-steps" ]; then if [ "${1:-}" = "--run-steps" ]; then
echo "${C_TITLE}===== 🧹 Cleanup-server (--run-steps) =====${C_RESET}" CURRENT_TARGET="${2:-local}"
echo "${C_TITLE}===== 🧹 Cleanup-server on ${CURRENT_TARGET} =====${C_RESET}"
echo "" echo ""
run_all_steps run_all_steps
echo "" echo ""