Add superadmin integration tests and env-based config
This commit is contained in:
parent
4f7903ddc9
commit
e5c1d38dfa
12
Makefile
12
Makefile
@ -7,8 +7,12 @@ MAIN_FILE := ./cmd/accountsvc/main.go
|
||||
PORT ?= 8080
|
||||
OS := $(shell uname -s)
|
||||
|
||||
# Load local environment overrides if present.
|
||||
-include .env
|
||||
export
|
||||
|
||||
DB_NAME := account
|
||||
DB_USER ?= $(or $(POSTGRES_USER),shenlan)
|
||||
DB_USER ?= $(or $(POSTGRES_USER),postgres)
|
||||
DB_PASS ?= $(or $(POSTGRES_PASSWORD),password)
|
||||
DB_HOST := 127.0.0.1
|
||||
DB_PORT := 15432
|
||||
@ -54,7 +58,7 @@ export APP_NAME MAIN_FILE PORT OS \
|
||||
# 🧩 基础命令
|
||||
# =========================================
|
||||
|
||||
.PHONY: all init build clean start stop restart dev test help \
|
||||
.PHONY: all init build clean start stop restart dev test help integration-test \
|
||||
init-go init-db init-db-core init-db-replication init-db-pglogical \
|
||||
stunnel-start \
|
||||
reinit-pglogical account-sync-push account-sync-pull account-sync-mirror create-db-user db-reset \
|
||||
@ -77,6 +81,7 @@ help:
|
||||
@echo "make reinit-pglogical 重新初始化 pglogical schema"
|
||||
@echo "make dev 热重载开发模式"
|
||||
@echo "make clean 清理构建产物"
|
||||
@echo "make integration-test 运行集成测试用例(初始化 + 创建管理员)"
|
||||
@echo "make cloudrun-build 构建并推送 Cloud Run 镜像"
|
||||
@echo "make cloudrun-deploy 部署 Cloud Run Service"
|
||||
@echo "make cloudrun-stunnel 更新 Cloud Run stunnel 配置 secret"
|
||||
@ -168,6 +173,9 @@ account-sync-mirror:
|
||||
create-super-admin:
|
||||
@bash scripts/create-super-admin.sh
|
||||
|
||||
integration-test:
|
||||
@bash integration-test/superadmin-login/run-test-scripts.sh
|
||||
|
||||
# =========================================
|
||||
# ⚙️ 编译与运行
|
||||
# =========================================
|
||||
|
||||
@ -31,7 +31,8 @@ server:
|
||||
|
||||
store:
|
||||
driver: "postgres"
|
||||
dsn: "postgres://shenlan:password@127.0.0.1:5432/account?sslmode=disable"
|
||||
# 提示:本地默认从 .env 读取 POSTGRES_USER / POSTGRES_PASSWORD
|
||||
dsn: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@127.0.0.1:5432/account?sslmode=disable"
|
||||
maxOpenConns: 30
|
||||
maxIdleConns: 10
|
||||
|
||||
|
||||
@ -24,6 +24,7 @@ server:
|
||||
- "https://www.svc.plus"
|
||||
- "https://global-homepage.svc.plus"
|
||||
- "https://accounts.svc.plus"
|
||||
- "https://console.svc.plus"
|
||||
- "https://localhost:8443"
|
||||
- "http://localhost:8080"
|
||||
- "http://127.0.0.1:8080"
|
||||
@ -41,7 +42,8 @@ server:
|
||||
|
||||
store:
|
||||
driver: "postgres"
|
||||
dsn: "postgres://shenlan:password@127.0.0.1:5432/account?sslmode=disable"
|
||||
# 提示:本地默认从 .env 读取 POSTGRES_USER / POSTGRES_PASSWORD
|
||||
dsn: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@127.0.0.1:5432/account?sslmode=disable"
|
||||
maxOpenConns: 30
|
||||
maxIdleConns: 10
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@
|
||||
|
||||
local:
|
||||
# 本地 PostgreSQL 连接地址,用于导入/导出账号数据
|
||||
dsn: "postgres://shenlan:password@127.0.0.1:5432/account?sslmode=disable"
|
||||
# 提示:本地默认从 .env 读取 POSTGRES_USER / POSTGRES_PASSWORD
|
||||
dsn: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@127.0.0.1:5432/account?sslmode=disable"
|
||||
# 可选:按 email 关键字过滤导出的账号
|
||||
email_keyword: ""
|
||||
# 导出的快照文件路径(默认 account-export.yaml)
|
||||
@ -47,4 +48,3 @@ remote:
|
||||
|
||||
# SSH 连接超时时间
|
||||
timeout: 30s
|
||||
|
||||
|
||||
@ -10,7 +10,8 @@
|
||||
|
||||
local:
|
||||
# 本地 PostgreSQL 连接地址,用于导入/导出账号数据
|
||||
dsn: "postgres://shenlan:password@127.0.0.1:5432/account?sslmode=disable"
|
||||
# 提示:本地默认从 .env 读取 POSTGRES_USER / POSTGRES_PASSWORD
|
||||
dsn: "postgres://${POSTGRES_USER}:${POSTGRES_PASSWORD}@127.0.0.1:5432/account?sslmode=disable"
|
||||
# 可选:按 email 关键字过滤导出的账号
|
||||
email_keyword: ""
|
||||
# 导出的快照文件路径(默认 account-export.yaml)
|
||||
@ -47,4 +48,3 @@ remote:
|
||||
|
||||
# SSH 连接超时时间
|
||||
timeout: 30s
|
||||
|
||||
|
||||
@ -20,7 +20,7 @@ spec:
|
||||
containers:
|
||||
# --- 主应用容器 ---
|
||||
- name: accounts-api
|
||||
image: asia-northeast1-docker.pkg.dev/xzerolab-480008/cloud-run-source-deploy/accounts.svc.plus/accounts-svc-plus:d5b6edcaa76150f2489bbdb2a46a41bc98baa87f
|
||||
image: asia-northeast1-docker.pkg.dev/xzerolab-480008/cloud-run-source-deploy/accounts.svc.plus/accounts-svc-plus:latest
|
||||
ports:
|
||||
- name: http1
|
||||
containerPort: 8080
|
||||
@ -48,7 +48,7 @@ spec:
|
||||
- name: POSTGRES_USER
|
||||
value: postgres
|
||||
- name: DB_NAME
|
||||
value: postgres
|
||||
value: account
|
||||
resources:
|
||||
limits:
|
||||
cpu: 1000m
|
||||
|
||||
66
integration-test/superadmin-login/README.md
Normal file
66
integration-test/superadmin-login/README.md
Normal file
@ -0,0 +1,66 @@
|
||||
# superadmin-login
|
||||
|
||||
## 说明
|
||||
|
||||
该用例用于本地集成测试,按顺序执行:
|
||||
|
||||
1. `make init-db`
|
||||
2. `make create-db-user`
|
||||
3. `make create-super-admin`
|
||||
|
||||
脚本会自动读取项目根目录 `.env` 中的环境变量(如 `POSTGRES_USER` / `POSTGRES_PASSWORD`),用于联动数据库配置。
|
||||
若未设置 `SUPERADMIN_PASSWORD`,脚本会生成随机密码并写回 `.env`,便于后续登录测试复用。
|
||||
|
||||
## 运行方式
|
||||
|
||||
```bash
|
||||
make integration-test
|
||||
```
|
||||
|
||||
或直接运行脚本:
|
||||
|
||||
```bash
|
||||
bash integration-test/superadmin-login/run-test-scripts.sh
|
||||
```
|
||||
|
||||
## API 自动化测试
|
||||
|
||||
```bash
|
||||
bash integration-test/superadmin-login/api-test.sh
|
||||
```
|
||||
|
||||
可选环境变量:
|
||||
|
||||
- `API_BASE_URL`:API 入口地址(默认 `https://accounts.svc.plus`)
|
||||
- `LOGIN_EMAIL`:登录邮箱(默认 `admin@svc.plus`)
|
||||
- `SUPERADMIN_PASSWORD`:登录密码(从 `.env` 读取)
|
||||
|
||||
## UI 自动化测试(Playwright)
|
||||
|
||||
```bash
|
||||
bash integration-test/superadmin-login/ui-test.sh
|
||||
```
|
||||
|
||||
可选环境变量:
|
||||
|
||||
- `UI_BASE_URL`:UI 入口地址(默认 `https://console.svc.plus`)
|
||||
- `LOGIN_EMAIL`:登录邮箱(默认 `admin@svc.plus`)
|
||||
- `SUPERADMIN_PASSWORD`:登录密码(从 `.env` 读取)
|
||||
|
||||
## 预期输出(示例)
|
||||
|
||||
```
|
||||
✅ 已读取 .env
|
||||
>>> init-db
|
||||
...(略)
|
||||
>>> create-super-admin
|
||||
...(略)
|
||||
✅ 集成测试步骤完成(DB 初始化 + 用户创建 + 超级管理员创建)
|
||||
|
||||
接下来手动登录验证:
|
||||
- 网址:https://console.svc.plus/login
|
||||
- 邮箱:admin@svc.plus
|
||||
- 密码:<generated-or-provided>
|
||||
```
|
||||
|
||||
> 注意:登录验证需要手动在浏览器完成。
|
||||
80
integration-test/superadmin-login/api-test.sh
Executable file
80
integration-test/superadmin-login/api-test.sh
Executable file
@ -0,0 +1,80 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
if [ -f .env ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
source .env
|
||||
set +a
|
||||
echo "✅ 已读取 .env"
|
||||
fi
|
||||
|
||||
if ! command -v curl >/dev/null; then
|
||||
echo "❌ 未找到 curl,请先安装或确保在 PATH 中" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
API_BASE_URL="${API_BASE_URL:-${BASE_URL:-https://accounts.svc.plus}}"
|
||||
LOGIN_EMAIL="${LOGIN_EMAIL:-admin@svc.plus}"
|
||||
LOGIN_PASSWORD="${SUPERADMIN_PASSWORD:-}"
|
||||
|
||||
if [ -z "$LOGIN_PASSWORD" ]; then
|
||||
echo "❌ 缺少 SUPERADMIN_PASSWORD(可写入 .env)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
login_payload=$(cat <<JSON
|
||||
{"email":"${LOGIN_EMAIL}","identifier":"${LOGIN_EMAIL}","password":"${LOGIN_PASSWORD}"}
|
||||
JSON
|
||||
)
|
||||
|
||||
login_response=$(curl -sS -w "\n%{http_code}" -X POST "${API_BASE_URL}/api/auth/login" \
|
||||
-H "Content-Type: application/json" \
|
||||
-d "$login_payload")
|
||||
|
||||
login_body=$(printf "%s" "$login_response" | sed '$d')
|
||||
login_status=$(printf "%s" "$login_response" | tail -n1)
|
||||
|
||||
if [ "$login_status" != "200" ]; then
|
||||
echo "❌ 登录失败: HTTP ${login_status}" >&2
|
||||
echo "$login_body" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if command -v python3 >/dev/null; then
|
||||
token=$(printf "%s" "$login_body" | python3 - <<'PY'
|
||||
import json, sys
|
||||
try:
|
||||
payload = json.load(sys.stdin)
|
||||
print(payload.get('token',''))
|
||||
except Exception:
|
||||
print('')
|
||||
PY
|
||||
)
|
||||
else
|
||||
echo "❌ 未找到 python3,无法解析登录 token" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ -z "$token" ]; then
|
||||
echo "❌ 登录响应中未包含 token" >&2
|
||||
echo "$login_body" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
session_response=$(curl -sS -w "\n%{http_code}" -X GET "${API_BASE_URL}/api/auth/session" \
|
||||
-H "Authorization: Bearer ${token}")
|
||||
|
||||
session_body=$(printf "%s" "$session_response" | sed '$d')
|
||||
session_status=$(printf "%s" "$session_response" | tail -n1)
|
||||
|
||||
if [ "$session_status" != "200" ]; then
|
||||
echo "❌ session 校验失败: HTTP ${session_status}" >&2
|
||||
echo "$session_body" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "✅ API 登录测试通过"
|
||||
74
integration-test/superadmin-login/run-test-scripts.sh
Executable file
74
integration-test/superadmin-login/run-test-scripts.sh
Executable file
@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
if [ -f .env ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
source .env
|
||||
set +a
|
||||
echo "✅ 已读取 .env"
|
||||
fi
|
||||
|
||||
ensure_superadmin_password() {
|
||||
if [ -n "${SUPERADMIN_PASSWORD:-}" ] && [ "${SUPERADMIN_PASSWORD}" != "ChangeMe" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if command -v openssl >/dev/null; then
|
||||
SUPERADMIN_PASSWORD="$(openssl rand -base64 12 | tr -d '\n' | tr '/+' 'Aa' | cut -c1-10)"
|
||||
else
|
||||
SUPERADMIN_PASSWORD="$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 10)"
|
||||
fi
|
||||
|
||||
if [ -f .env ]; then
|
||||
if grep -q '^SUPERADMIN_PASSWORD=' .env; then
|
||||
tmpfile="$(mktemp)"
|
||||
sed "s/^SUPERADMIN_PASSWORD=.*/SUPERADMIN_PASSWORD=${SUPERADMIN_PASSWORD}/" .env > "$tmpfile"
|
||||
mv "$tmpfile" .env
|
||||
else
|
||||
printf "\nSUPERADMIN_PASSWORD=%s\n" "$SUPERADMIN_PASSWORD" >> .env
|
||||
fi
|
||||
else
|
||||
printf "SUPERADMIN_PASSWORD=%s\n" "$SUPERADMIN_PASSWORD" > .env
|
||||
fi
|
||||
echo "✅ 已写入 .env 的 SUPERADMIN_PASSWORD"
|
||||
}
|
||||
|
||||
if ! command -v make >/dev/null; then
|
||||
echo "❌ 未找到 make,请先安装或确保在 PATH 中" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo ">>> init-db"
|
||||
make init-db
|
||||
|
||||
echo ">>> create-db-user"
|
||||
make create-db-user
|
||||
|
||||
echo ">>> create-super-admin"
|
||||
ensure_superadmin_password
|
||||
export SUPERADMIN_PASSWORD
|
||||
create_output="$(make create-super-admin 2>&1 | tee /dev/stderr)"
|
||||
|
||||
superadmin_password=""
|
||||
if echo "$create_output" | grep -q "已生成随机初始密码"; then
|
||||
superadmin_password="$(echo "$create_output" | sed -n 's/.*已生成随机初始密码: \([A-Za-z0-9]\+\).*/\1/p' | tail -n1)"
|
||||
fi
|
||||
if [ -z "$superadmin_password" ]; then
|
||||
superadmin_password="$(echo "$create_output" | sed -n 's/.*密码:\s*//p' | tail -n1)"
|
||||
fi
|
||||
|
||||
cat <<EOM
|
||||
|
||||
✅ 集成测试步骤完成(DB 初始化 + 用户创建 + 超级管理员创建)
|
||||
|
||||
接下来手动登录验证:
|
||||
- 网址:https://console.svc.plus/login
|
||||
- 邮箱:admin@svc.plus
|
||||
- 密码:${superadmin_password:-请查看上方 create-super-admin 输出}
|
||||
|
||||
提示:如果页面无法访问,请先确保 account 服务已启动并对外可用。
|
||||
EOM
|
||||
101
integration-test/superadmin-login/ui-test.sh
Executable file
101
integration-test/superadmin-login/ui-test.sh
Executable file
@ -0,0 +1,101 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
if [ -f .env ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
source .env
|
||||
set +a
|
||||
echo "✅ 已读取 .env"
|
||||
fi
|
||||
|
||||
if ! command -v node >/dev/null; then
|
||||
echo "❌ 未找到 node,请先安装" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! command -v npx >/dev/null; then
|
||||
echo "❌ 未找到 npx,请先安装" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
UI_BASE_URL="${UI_BASE_URL:-${BASE_URL:-https://console.svc.plus}}"
|
||||
LOGIN_EMAIL="${LOGIN_EMAIL:-admin@svc.plus}"
|
||||
LOGIN_PASSWORD="${SUPERADMIN_PASSWORD:-}"
|
||||
|
||||
if [ -z "$LOGIN_PASSWORD" ]; then
|
||||
echo "❌ 缺少 SUPERADMIN_PASSWORD(可写入 .env)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMP_DIR="${TMPDIR:-/tmp}"
|
||||
PLAYWRIGHT_TEST_DIR="${TMP_DIR}/xcontrol-playwright-login"
|
||||
mkdir -p "$PLAYWRIGHT_TEST_DIR"
|
||||
|
||||
cat <<'TEST' > "$PLAYWRIGHT_TEST_DIR/login.spec.mjs"
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
test.use({ screenshot: 'only-on-failure' });
|
||||
|
||||
test('superadmin login', async ({ page }) => {
|
||||
const baseUrl = process.env.UI_BASE_URL || process.env.BASE_URL || 'https://console.svc.plus';
|
||||
const email = process.env.LOGIN_EMAIL || 'admin@svc.plus';
|
||||
const password = process.env.SUPERADMIN_PASSWORD;
|
||||
|
||||
if (!password) {
|
||||
throw new Error('missing SUPERADMIN_PASSWORD');
|
||||
}
|
||||
|
||||
await page.goto(`${baseUrl}/login`, { waitUntil: 'domcontentloaded' });
|
||||
|
||||
const emailByRole = page.getByRole('textbox', { name: /email|邮箱|账号|用户名|identifier/i });
|
||||
const emailBySelector = page.locator(
|
||||
'input[type="email"], input[name="email"], input[name="identifier"], input[placeholder*="邮箱"], input[placeholder*="Email"], input[type="text"]'
|
||||
);
|
||||
const emailInput = (await emailByRole.count()) > 0 ? emailByRole.first() : emailBySelector.first();
|
||||
await expect(emailInput).toBeVisible({ timeout: 15000 });
|
||||
await emailInput.fill(email);
|
||||
|
||||
const passwordInput = page.locator(
|
||||
'input[type="password"], input[name="password"], input[placeholder*="密码"], input[placeholder*="Password"]'
|
||||
);
|
||||
await expect(passwordInput).toBeVisible({ timeout: 15000 });
|
||||
await passwordInput.fill(password);
|
||||
|
||||
const submitBtn = page.locator(
|
||||
'button[type="submit"], button:has-text("登录"), button:has-text("Log in"), button:has-text("Sign in")'
|
||||
);
|
||||
await expect(submitBtn).toBeVisible({ timeout: 15000 });
|
||||
await submitBtn.click();
|
||||
|
||||
await page.waitForLoadState('networkidle');
|
||||
await expect(page).not.toHaveURL(/login/);
|
||||
});
|
||||
TEST
|
||||
|
||||
cd "$PLAYWRIGHT_TEST_DIR"
|
||||
|
||||
if [ ! -f package.json ]; then
|
||||
cat <<'PKG' > package.json
|
||||
{
|
||||
"name": "xcontrol-playwright-login",
|
||||
"private": true,
|
||||
"version": "0.0.0",
|
||||
"type": "module",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "^1.49.0"
|
||||
}
|
||||
}
|
||||
PKG
|
||||
fi
|
||||
|
||||
npm install --silent
|
||||
npx playwright install chromium
|
||||
|
||||
UI_BASE_URL="$UI_BASE_URL" BASE_URL="$UI_BASE_URL" LOGIN_EMAIL="$LOGIN_EMAIL" SUPERADMIN_PASSWORD="$LOGIN_PASSWORD" \
|
||||
npx playwright test login.spec.mjs
|
||||
|
||||
echo "✅ UI 登录测试通过"
|
||||
@ -3,13 +3,34 @@ set -euo pipefail
|
||||
|
||||
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/_common.sh"
|
||||
|
||||
if [ -z "${SUPERADMIN_USERNAME}" ] || [ -z "${SUPERADMIN_PASSWORD}" ]; then
|
||||
echo "❌ 请指定用户名与密码"
|
||||
exit 1
|
||||
SUPERADMIN_EMAIL="admin@svc.plus"
|
||||
SUPERADMIN_USERNAME="${SUPERADMIN_USERNAME:-Admin}"
|
||||
|
||||
if [ -z "${SUPERADMIN_PASSWORD:-}" ] || [ "${SUPERADMIN_PASSWORD}" = "ChangeMe" ]; then
|
||||
if command -v openssl >/dev/null; then
|
||||
SUPERADMIN_PASSWORD="$(openssl rand -base64 12 | tr -d '\n' | tr '/+' 'Aa' | cut -c1-10)"
|
||||
else
|
||||
SUPERADMIN_PASSWORD="$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 10)"
|
||||
fi
|
||||
echo "⚠️ 未指定 SUPERADMIN_PASSWORD,已生成随机初始密码: ${SUPERADMIN_PASSWORD}"
|
||||
fi
|
||||
|
||||
if psql "${DB_URL}" -Atc "SELECT 1 FROM users WHERE username='${SUPERADMIN_USERNAME}' OR email='${SUPERADMIN_EMAIL}' LIMIT 1" | grep -qx '1'; then
|
||||
echo "⚠️ 超级管理员已存在,跳过创建"
|
||||
if [ -z "${SUPERADMIN_CURRENT_PASSWORD:-}" ]; then
|
||||
echo "⚠️ 超级管理员已存在,未提供 SUPERADMIN_CURRENT_PASSWORD,跳过更新"
|
||||
exit 0
|
||||
fi
|
||||
go run ./cmd/createadmin/main.go \
|
||||
--driver postgres \
|
||||
--dsn "${DB_URL}" \
|
||||
--username "${SUPERADMIN_USERNAME}" \
|
||||
--password "${SUPERADMIN_PASSWORD}" \
|
||||
--email "${SUPERADMIN_EMAIL}" \
|
||||
--current-password "${SUPERADMIN_CURRENT_PASSWORD}"
|
||||
echo "✅ 登录信息(仅本次输出)"
|
||||
echo " 网址:https://console.svc.plus/login"
|
||||
echo " 邮箱:admin@svc.plus"
|
||||
echo " 密码:${SUPERADMIN_PASSWORD}"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
@ -19,3 +40,8 @@ go run ./cmd/createadmin/main.go \
|
||||
--username "${SUPERADMIN_USERNAME}" \
|
||||
--password "${SUPERADMIN_PASSWORD}" \
|
||||
--email "${SUPERADMIN_EMAIL}"
|
||||
|
||||
echo "✅ 登录信息(仅本次输出)"
|
||||
echo " 网址:https://console.svc.plus/login"
|
||||
echo " 邮箱:admin@svc.plus"
|
||||
echo " 密码:${SUPERADMIN_PASSWORD}"
|
||||
|
||||
@ -13,7 +13,7 @@ set -euo pipefail
|
||||
# 配置参数(可通过环境变量覆盖)
|
||||
# -----------------------------------------------------------------------------
|
||||
DB_NAME="${DB_NAME:-account}"
|
||||
DB_USER="${DB_USER:-shenlan}"
|
||||
DB_USER="${DB_USER:-${POSTGRES_USER:-postgres}}"
|
||||
DB_PASS="${DB_PASS:-password}"
|
||||
DB_PORT="${DB_PORT:-5432}"
|
||||
DB_HOST="${DB_HOST:-127.0.0.1}"
|
||||
|
||||
@ -67,9 +67,9 @@ go run ./cmd/migratectl/main.go check --cn "$CN_DSN" --global "$GLOBAL_DSN"
|
||||
make -C account init-pglogical-region \
|
||||
REGION_DB_URL="$REGION_DB_URL" \
|
||||
NODE_NAME=node_cn \
|
||||
NODE_DSN="host=cn-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx" \
|
||||
NODE_DSN="host=cn-homepage.svc.plus port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}" \
|
||||
SUBSCRIPTION_NAME=sub_from_global \
|
||||
PROVIDER_DSN="host=global-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx"
|
||||
PROVIDER_DSN="host=global-homepage.svc.plus port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}"
|
||||
```
|
||||
|
||||
4. 在另一侧节点重复执行并互为订阅,实现双主写入。
|
||||
@ -85,21 +85,21 @@ pglogical schema 与业务 schema 分离,以防逻辑复制函数污染业务
|
||||
bash
|
||||
复制代码
|
||||
sudo -u postgres psql -d account -c "GRANT USAGE ON SCHEMA pglogical TO PUBLIC;"
|
||||
2️⃣ 授权业务用户(shenlan)
|
||||
2️⃣ 授权业务用户(app_user)
|
||||
sql
|
||||
复制代码
|
||||
-- 登录 postgres
|
||||
sudo -u postgres psql -d account
|
||||
|
||||
-- 授权 shenlan 对 public schema 全权限
|
||||
ALTER SCHEMA public OWNER TO shenlan;
|
||||
GRANT ALL ON SCHEMA public TO shenlan;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO shenlan;
|
||||
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO shenlan;
|
||||
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO shenlan;
|
||||
-- 授权 app_user 对 public schema 全权限
|
||||
ALTER SCHEMA public OWNER TO app_user;
|
||||
GRANT ALL ON SCHEMA public TO app_user;
|
||||
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO app_user;
|
||||
GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO app_user;
|
||||
GRANT ALL PRIVILEGES ON ALL FUNCTIONS IN SCHEMA public TO app_user;
|
||||
|
||||
-- 授权 pglogical schema 使用权限(仅使用,不可修改)
|
||||
GRANT USAGE ON SCHEMA pglogical TO shenlan;
|
||||
GRANT USAGE ON SCHEMA pglogical TO app_user;
|
||||
|
||||
\q
|
||||
⚙️ 执行顺序建议
|
||||
@ -123,17 +123,17 @@ GRANT USAGE ON SCHEMA pglogical TO shenlan;
|
||||
# Global 节点示例
|
||||
psql "$REGION_GLOBAL_DB_URL" -v ON_ERROR_STOP=1 \
|
||||
-v NODE_NAME=node_global \
|
||||
-v NODE_DSN='host=global-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx' \
|
||||
-v NODE_DSN='host=global-homepage.svc.plus port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}' \
|
||||
-v SUBSCRIPTION_NAME=sub_from_cn \
|
||||
-v PROVIDER_DSN='host=cn-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx' \
|
||||
-v PROVIDER_DSN='host=cn-homepage.svc.plus port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}' \
|
||||
-f account/sql/schema_pglogical_region.sql
|
||||
|
||||
# CN 节点示例
|
||||
psql "$REGION_CN_DB_URL" -v ON_ERROR_STOP=1 \
|
||||
-v NODE_NAME=node_cn \
|
||||
-v NODE_DSN='host=cn-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxxx' \
|
||||
-v NODE_DSN='host=cn-homepage.svc.plus port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}' \
|
||||
-v SUBSCRIPTION_NAME=sub_from_global \
|
||||
-v PROVIDER_DSN='host=global-homepage.svc.plus port=5432 dbname=account user=pglogical password=xxx' \
|
||||
-v PROVIDER_DSN='host=global-homepage.svc.plus port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}' \
|
||||
-f account/sql/schema_pglogical_region.sql
|
||||
```
|
||||
|
||||
@ -143,12 +143,12 @@ psql "$REGION_CN_DB_URL" -v ON_ERROR_STOP=1 \
|
||||
make init-pglogical-region \
|
||||
REGION_DB_URL="$REGION_DB_URL" \
|
||||
NODE_NAME=node_example \
|
||||
NODE_DSN="host=example port=5432 dbname=account user=pglogical password=secret" \
|
||||
NODE_DSN="host=example port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}" \
|
||||
SUBSCRIPTION_NAME=sub_from_peer \
|
||||
PROVIDER_DSN="host=peer port=5432 dbname=account user=pglogical password=secret"
|
||||
PROVIDER_DSN="host=peer port=5432 dbname=account user=${PGLOGICAL_USER} password=${PGLOGICAL_PASSWORD}"
|
||||
```
|
||||
|
||||
- 若使用业务账号(如 `shenlan`)执行初始化,PostgreSQL 会提示缺少超级用户权限并跳过 `pglogical` 初始化。
|
||||
- 若使用业务账号(如 `app_user`)执行初始化,PostgreSQL 会提示缺少超级用户权限并跳过 `pglogical` 初始化。
|
||||
- 建议改用 `postgres` 等超级用户连接执行,或由管理员预先安装 `pglogical` 扩展并授予业务用户访问权限。
|
||||
- 如果扩展已由管理员创建,可直接重新运行 `make init-pglogical-region-cn` 完成复制集与订阅配置。
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user