|
9 | 9 | # sudo ./pgpro-setup.sh ← интерактивное меню |
10 | 10 | # sudo ./pgpro-setup.sh install ← установка (спросит версию) |
11 | 11 | # sudo ./pgpro-setup.sh add-instance ← добавить экземпляр |
| 12 | +# sudo ./pgpro-setup.sh delete-instance ← удалить экземпляр |
12 | 13 | # sudo ./pgpro-setup.sh list ← список экземпляров |
13 | 14 | # |
14 | 15 | # Переменные окружения (можно переопределить): |
@@ -143,45 +144,51 @@ detect_installed_version() { |
143 | 144 | # ─────────────────────────────────────────────── |
144 | 145 | # СПИСОК ЭКЗЕМПЛЯРОВ |
145 | 146 | # ─────────────────────────────────────────────── |
| 147 | +# Единая таблица по всем установленным версиям Postgres Pro. |
146 | 148 | list_instances() { |
147 | | - local ver="${1}" |
148 | | - header "═══ Экземпляры Postgres Pro-${ver} ═══" |
149 | | - |
150 | | - local files=() |
151 | | - mapfile -t files < <( |
152 | | - find /etc/default -maxdepth 1 -name "postgrespro-${ver}*" \ |
153 | | - ! -name "*.dpkg*" ! -name "*.bak" 2>/dev/null | sort |
154 | | - ) |
155 | | - if [[ ${#files[@]} -eq 0 ]]; then |
156 | | - warn "Файлы окружения не найдены в /etc/default — экземпляров нет." |
| 149 | + header "═══ Экземпляры Postgres Pro ═══" |
| 150 | + |
| 151 | + local vers=() |
| 152 | + mapfile -t vers < <(find /opt/pgpro -maxdepth 1 -mindepth 1 -type d -printf '%f\n' 2>/dev/null | sort) |
| 153 | + if [[ ${#vers[@]} -eq 0 ]]; then |
| 154 | + warn "Установок Postgres Pro не найдено (/opt/pgpro пуст)." |
157 | 155 | return |
158 | 156 | fi |
159 | 157 |
|
160 | | - printf "${BOLD}%-22s %-6s %-40s %-9s${RESET}\n" "СЕРВИС" "ПОРТ" "PGDATA" "СТАТУС" |
161 | | - printf '%s\n' "$(printf '─%.0s' {1..82})" |
162 | | - |
163 | | - local f base pgdata pgport svc status |
164 | | - for f in "${files[@]}"; do |
165 | | - pgdata=$(grep -E "^PGDATA=" "$f" 2>/dev/null | head -1 | sed "s/^PGDATA=//;s/['\"]//g") |
166 | | - base=$(basename "$f") |
167 | | - if [[ "$base" =~ -([0-9]{4,5})$ ]]; then |
168 | | - pgport="${BASH_REMATCH[1]}" |
169 | | - svc="postgrespro-${ver}@${pgport}" |
170 | | - else |
171 | | - pgport="5432" |
172 | | - svc="postgrespro-${ver}" |
173 | | - fi |
174 | | - if systemctl is-active --quiet "${svc}" 2>/dev/null; then |
175 | | - status="${GREEN}running${RESET}" |
176 | | - elif systemctl is-enabled --quiet "${svc}" 2>/dev/null; then |
177 | | - status="${YELLOW}stopped${RESET}" |
178 | | - else |
179 | | - status="${RED}unknown${RESET}" |
180 | | - fi |
181 | | - printf "%-22s %-6s %-40s %b\n" "${svc}" "${pgport}" "${pgdata:-—}" "${status}" |
| 158 | + printf "${BOLD}%-8s %-24s %-6s %-34s %-9s${RESET}\n" \ |
| 159 | + "ВЕРСИЯ" "СЕРВИС" "ПОРТ" "PGDATA" "СТАТУС" |
| 160 | + printf '%s\n' "$(printf '─%.0s' {1..92})" |
| 161 | + |
| 162 | + local total=0 ver f base port svc pgdata status |
| 163 | + for ver in "${vers[@]}"; do |
| 164 | + local files=() |
| 165 | + mapfile -t files < <( |
| 166 | + find /etc/default -maxdepth 1 \ |
| 167 | + \( -name "postgrespro-${ver}" -o -name "postgrespro-${ver}-*" \) \ |
| 168 | + ! -name "*.dpkg*" ! -name "*.bak" 2>/dev/null | sort |
| 169 | + ) |
| 170 | + for f in "${files[@]}"; do |
| 171 | + base=$(basename "$f") |
| 172 | + if [[ "$base" == "postgrespro-${ver}" ]]; then |
| 173 | + port="5432"; svc="postgrespro-${ver}" |
| 174 | + else |
| 175 | + port="${base##postgrespro-"${ver}"-}"; svc="postgrespro-${ver}@${port}" |
| 176 | + fi |
| 177 | + pgdata=$(grep -E "^PGDATA=" "$f" 2>/dev/null | head -1 | sed "s/^PGDATA=//;s/['\"]//g") |
| 178 | + if systemctl is-active --quiet "${svc}" 2>/dev/null; then |
| 179 | + status="${GREEN}running${RESET}" |
| 180 | + elif systemctl is-enabled --quiet "${svc}" 2>/dev/null; then |
| 181 | + status="${YELLOW}stopped${RESET}" |
| 182 | + else |
| 183 | + status="${RED}unknown${RESET}" |
| 184 | + fi |
| 185 | + printf "%-8s %-24s %-6s %-34s %b\n" \ |
| 186 | + "${ver}" "${svc}" "${port}" "${pgdata:-—}" "${status}" |
| 187 | + (( total++ )) || true |
| 188 | + done |
182 | 189 | done |
183 | | - printf '%s\n' "$(printf '─%.0s' {1..82})" |
184 | | - echo "" |
| 190 | + printf '%s\n' "$(printf '─%.0s' {1..92})" |
| 191 | + echo -e "Итого: ${BOLD}${total}${RESET} экземпляр(ов)\n" |
185 | 192 | } |
186 | 193 |
|
187 | 194 | # ─────────────────────────────────────────────── |
@@ -258,7 +265,7 @@ cmd_install() { |
258 | 265 | # Предупреждение, если уже установлено |
259 | 266 | if [[ -x "${PG_BIN}/postgres" ]]; then |
260 | 267 | warn "Postgres Pro ${PGVER} уже установлен (${PG_BIN})." |
261 | | - confirm "Продолжить всё равно?" || { log "Отменено."; exit 0; } |
| 268 | + confirm "Продолжить всё равно?" || { log "Отменено."; return 0; } |
262 | 269 | fi |
263 | 270 |
|
264 | 271 | # Доп. шаги (по умолчанию включены, как было выбрано) |
@@ -375,7 +382,7 @@ cmd_add_instance() { |
375 | 382 | PG_BIN="$(pg_bin "${PGVER}")" |
376 | 383 | [[ -x "${PG_BIN}/initdb" ]] || die "initdb не найден: ${PG_BIN}/initdb (версия установлена?)" |
377 | 384 |
|
378 | | - list_instances "${PGVER}" |
| 385 | + list_instances |
379 | 386 |
|
380 | 387 | # Порт |
381 | 388 | while true; do |
@@ -427,7 +434,7 @@ cmd_add_instance() { |
427 | 434 | printf " %-12s %s\n" "Порт:" "${PGPORT}" |
428 | 435 | printf " %-12s %s\n" "PGDATA:" "${PGDATA_NEW}" |
429 | 436 | echo "" |
430 | | - confirm "Создать экземпляр?" || { log "Отменено."; exit 0; } |
| 437 | + confirm "Создать экземпляр?" || { log "Отменено."; return 0; } |
431 | 438 |
|
432 | 439 | # ── Шаг 1: шаблон unit ── |
433 | 440 | header "Шаг 1: шаблонный unit ${SVC_TEMPLATE}" |
@@ -488,46 +495,144 @@ EOF |
488 | 495 | fi |
489 | 496 |
|
490 | 497 | header "✅ Экземпляр на порту ${PGPORT} создан" |
491 | | - list_instances "${PGVER}" |
| 498 | + list_instances |
492 | 499 | } |
493 | 500 |
|
494 | 501 | # ─────────────────────────────────────────────── |
495 | 502 | # КОМАНДА: СПИСОК |
496 | 503 | # ─────────────────────────────────────────────── |
497 | 504 | cmd_list() { |
498 | 505 | require_root |
499 | | - detect_installed_version |
500 | | - list_instances "${PGVER}" |
| 506 | + list_instances |
| 507 | +} |
| 508 | + |
| 509 | +# ─────────────────────────────────────────────── |
| 510 | +# КОМАНДА: УДАЛИТЬ ЭКЗЕМПЛЯР |
| 511 | +# ─────────────────────────────────────────────── |
| 512 | +cmd_delete_instance() { |
| 513 | + require_root |
| 514 | + |
| 515 | + # Собираем все дополнительные экземпляры (с портом) по всем версиям |
| 516 | + local vers=() entries=() ver f base port |
| 517 | + mapfile -t vers < <(find /opt/pgpro -maxdepth 1 -mindepth 1 -type d -printf '%f\n' 2>/dev/null | sort) |
| 518 | + for ver in "${vers[@]}"; do |
| 519 | + local files=() |
| 520 | + mapfile -t files < <( |
| 521 | + find /etc/default -maxdepth 1 -name "postgrespro-${ver}-*" \ |
| 522 | + ! -name "*.dpkg*" ! -name "*.bak" 2>/dev/null | sort |
| 523 | + ) |
| 524 | + for f in "${files[@]}"; do |
| 525 | + base=$(basename "$f") |
| 526 | + port="${base##postgrespro-"${ver}"-}" |
| 527 | + [[ "$port" =~ ^[0-9]{4,5}$ ]] || continue |
| 528 | + entries+=("${ver}|${port}") |
| 529 | + done |
| 530 | + done |
| 531 | + |
| 532 | + list_instances |
| 533 | + |
| 534 | + if [[ ${#entries[@]} -eq 0 ]]; then |
| 535 | + warn "Дополнительных экземпляров нет. Базовый кластер (порт 5432) удаляется через apt." |
| 536 | + return |
| 537 | + fi |
| 538 | + |
| 539 | + header "Выберите экземпляр для удаления:" |
| 540 | + local i=1 e |
| 541 | + for e in "${entries[@]}"; do |
| 542 | + printf " ${BOLD}%2d${RESET}) postgrespro-%s@%s\n" "$i" "${e%%|*}" "${e##*|}" |
| 543 | + (( i++ )) || true |
| 544 | + done |
| 545 | + printf " ${BOLD}%2d${RESET}) отмена\n" "$i" |
| 546 | + |
| 547 | + local choice |
| 548 | + read -rp "$(echo -e "${CYAN}Экземпляр${RESET}: ")" choice |
| 549 | + if ! [[ "$choice" =~ ^[0-9]+$ ]] || (( choice < 1 || choice > ${#entries[@]} )); then |
| 550 | + log "Отменено."; return |
| 551 | + fi |
| 552 | + |
| 553 | + local sel="${entries[choice-1]}" |
| 554 | + local del_ver="${sel%%|*}" |
| 555 | + local PGPORT="${sel##*|}" |
| 556 | + local SVC="postgrespro-${del_ver}@${PGPORT}" |
| 557 | + local ENV_FILE="/etc/default/postgrespro-${del_ver}-${PGPORT}" |
| 558 | + local OVERRIDE_DIR="/etc/systemd/system/${SVC}.service.d" |
| 559 | + local PGDATA |
| 560 | + PGDATA=$(grep -E "^PGDATA=" "$ENV_FILE" 2>/dev/null | head -1 | sed "s/^PGDATA=//;s/['\"]//g") |
| 561 | + |
| 562 | + echo "" |
| 563 | + warn "Будет удалён экземпляр ${SVC} (порт ${PGPORT})." |
| 564 | + printf " PGDATA: %s\n" "${PGDATA:-—}" |
| 565 | + confirm "Остановить экземпляр и удалить его конфигурацию?" || { log "Отменено."; return; } |
| 566 | + |
| 567 | + log "Остановка и отключение ${SVC}" |
| 568 | + systemctl stop "${SVC}" 2>/dev/null || true |
| 569 | + systemctl disable "${SVC}" 2>/dev/null || true |
| 570 | + |
| 571 | + log "Удаление override и файла окружения" |
| 572 | + rm -rf "${OVERRIDE_DIR}" |
| 573 | + rm -f "${ENV_FILE}" |
| 574 | + systemctl daemon-reload |
| 575 | + systemctl reset-failed "${SVC}" 2>/dev/null || true |
| 576 | + |
| 577 | + if [[ -n "${PGDATA}" && -d "${PGDATA}" ]]; then |
| 578 | + if confirm "Удалить каталог данных ${PGDATA}? Это НЕОБРАТИМО"; then |
| 579 | + rm -rf "${PGDATA}" |
| 580 | + log "Каталог данных удалён: ${PGDATA}" |
| 581 | + else |
| 582 | + warn "Каталог данных оставлен: ${PGDATA}" |
| 583 | + fi |
| 584 | + fi |
| 585 | + |
| 586 | + header "✅ Экземпляр ${SVC} удалён" |
| 587 | + list_instances |
501 | 588 | } |
502 | 589 |
|
503 | 590 | # ─────────────────────────────────────────────── |
504 | 591 | # МЕНЮ |
505 | 592 | # ─────────────────────────────────────────────── |
506 | | -main_menu() { |
507 | | - header "═══ Postgres Pro: установка и экземпляры ═══" |
508 | | - echo " 1) Установить Postgres Pro (выбор версии)" |
509 | | - echo " 2) Добавить экземпляр (instance)" |
510 | | - echo " 3) Показать экземпляры" |
| 593 | +# Показ экземпляров с возвратом в меню или выходом (скрипт сам не закрывается). |
| 594 | +menu_list() { |
| 595 | + list_instances |
| 596 | + echo " 1) Назад в меню" |
511 | 597 | echo " 0) Выход" |
512 | | - local choice |
513 | | - read -rp "$(echo -e "${CYAN}Действие${RESET} [1]: ")" choice |
514 | | - case "${choice:-1}" in |
515 | | - 1) cmd_install ;; |
516 | | - 2) cmd_add_instance ;; |
517 | | - 3) cmd_list ;; |
| 598 | + local c |
| 599 | + read -rp "$(echo -e "${CYAN}Действие${RESET} [1]: ")" c |
| 600 | + case "${c:-1}" in |
518 | 601 | 0) exit 0 ;; |
519 | | - *) die "Неизвестный пункт меню: ${choice}" ;; |
| 602 | + *) return 0 ;; |
520 | 603 | esac |
521 | 604 | } |
522 | 605 |
|
| 606 | +main_menu() { |
| 607 | + while true; do |
| 608 | + header "═══ Postgres Pro: установка и экземпляры ═══" |
| 609 | + echo " 1) Установить Postgres Pro (выбор версии)" |
| 610 | + echo " 2) Добавить экземпляр (instance)" |
| 611 | + echo " 3) Показать экземпляры" |
| 612 | + echo " 4) Удалить экземпляр (instance)" |
| 613 | + echo " 0) Выход" |
| 614 | + local choice |
| 615 | + read -rp "$(echo -e "${CYAN}Действие${RESET} [1]: ")" choice |
| 616 | + case "${choice:-1}" in |
| 617 | + 1) cmd_install ;; |
| 618 | + 2) cmd_add_instance ;; |
| 619 | + 3) menu_list ;; |
| 620 | + 4) cmd_delete_instance ;; |
| 621 | + 0) exit 0 ;; |
| 622 | + *) warn "Неизвестный пункт меню: ${choice}" ;; |
| 623 | + esac |
| 624 | + done |
| 625 | +} |
| 626 | + |
523 | 627 | # ─────────────────────────────────────────────── |
524 | 628 | # ТОЧКА ВХОДА |
525 | 629 | # ─────────────────────────────────────────────── |
526 | 630 | case "${1:-menu}" in |
527 | | - install) cmd_install ;; |
528 | | - add-instance|add) cmd_add_instance ;; |
529 | | - list|ls) cmd_list ;; |
530 | | - menu|"") require_root; main_menu ;; |
| 631 | + install) cmd_install ;; |
| 632 | + add-instance|add) cmd_add_instance ;; |
| 633 | + delete-instance|del|rm) cmd_delete_instance ;; |
| 634 | + list|ls) cmd_list ;; |
| 635 | + menu|"") require_root; main_menu ;; |
531 | 636 | -h|--help|help) |
532 | 637 | grep -E '^#( |$)' "$0" | sed -E 's/^# ?//' |
533 | 638 | ;; |
|
0 commit comments