- Add Workspace domain (entity, repository, service, handler, DTO) - Add multi-tenant K8s client with tenant binding and quota management - Add K8s diagnostics client (instance diagnostics) - Add authorization middleware (authz package) - Restructure frontend to feature-based architecture (features/) - Add User Management page in configuration - Add AccessDenied page and route guards - Refactor shared components (form inputs, layout, UI) - Update Tailwind config for new design system - Add comprehensive documentation (docs/, tasks/, plans) - Improve cluster service with better kubeconfig handling - Add tests for crypto, config, helm client, tenant binding
261 lines
8.0 KiB
Bash
Executable File
261 lines
8.0 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
# generate-bootstrap-config.sh
|
|
# 从 kubeconfig 生成 bootstrap 配置文件
|
|
|
|
set -e
|
|
|
|
echo "🔧 OCDP Bootstrap Configuration Generator"
|
|
echo "========================================"
|
|
echo ""
|
|
|
|
# 检查依赖
|
|
command -v kubectl >/dev/null 2>&1 || { echo "❌ kubectl is required but not installed. Aborting." >&2; exit 1; }
|
|
command -v jq >/dev/null 2>&1 || { echo "❌ jq is required but not installed. Aborting." >&2; exit 1; }
|
|
|
|
# 默认输出文件
|
|
OUTPUT_FILE="${1:-config/bootstrap.json}"
|
|
|
|
# 临时文件
|
|
TMP_FILE=$(mktemp)
|
|
|
|
# 创建基础配置结构
|
|
cat > "$TMP_FILE" <<'EOF'
|
|
{
|
|
"enabled": true,
|
|
"users": [],
|
|
"registries": [],
|
|
"clusters": []
|
|
}
|
|
EOF
|
|
|
|
echo "📋 请按提示输入信息..."
|
|
echo ""
|
|
|
|
# ===== Admin 用户配置 =====
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "👤 Admin 用户配置"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
read -p "是否添加初始管理员用户? (y/n) [y]: " ADD_ADMIN
|
|
ADD_ADMIN=${ADD_ADMIN:-y}
|
|
|
|
if [[ "$ADD_ADMIN" == "y" ]]; then
|
|
read -p "Admin 用户名: " ADMIN_USER
|
|
read -sp "Admin 密码: " ADMIN_PASS
|
|
echo ""
|
|
read -p "Admin 邮箱 [${ADMIN_USER}@example.local]: " ADMIN_EMAIL
|
|
ADMIN_EMAIL=${ADMIN_EMAIL:-"${ADMIN_USER}@example.local"}
|
|
|
|
if [[ -z "$ADMIN_USER" || -z "$ADMIN_PASS" ]]; then
|
|
echo "❌ Admin 用户名和密码不能为空"
|
|
exit 1
|
|
fi
|
|
|
|
TMP_USER=$(jq -n \
|
|
--arg username "$ADMIN_USER" \
|
|
--arg password "$ADMIN_PASS" \
|
|
--arg email "$ADMIN_EMAIL" \
|
|
'{username: $username, password: $password, email: $email}')
|
|
|
|
jq ".users += [$TMP_USER]" "$TMP_FILE" > "${TMP_FILE}.tmp" && mv "${TMP_FILE}.tmp" "$TMP_FILE"
|
|
echo "✅ Admin 用户 '$ADMIN_USER' 已添加"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ===== Registries 配置 =====
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "📦 Registry 配置"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
read -p "是否添加 Registry? (y/n) [y]: " ADD_REGISTRY
|
|
ADD_REGISTRY=${ADD_REGISTRY:-y}
|
|
|
|
if [[ "$ADD_REGISTRY" == "y" ]]; then
|
|
read -p "Registry 名称 [harbor]: " REGISTRY_NAME
|
|
REGISTRY_NAME=${REGISTRY_NAME:-harbor}
|
|
|
|
read -p "Registry URL: " REGISTRY_URL
|
|
|
|
read -p "Registry 描述 [Harbor Registry]: " REGISTRY_DESC
|
|
REGISTRY_DESC=${REGISTRY_DESC:-"Harbor Registry"}
|
|
|
|
read -p "Registry 用户名(推荐 Harbor robot 账号): " REGISTRY_USER
|
|
|
|
read -sp "Registry 密码: " REGISTRY_PASS
|
|
echo ""
|
|
|
|
if [[ -z "$REGISTRY_URL" ]]; then
|
|
echo "❌ Registry URL 不能为空"
|
|
exit 1
|
|
fi
|
|
|
|
read -p "是否跳过 SSL 验证? (y/n) [n]: " REGISTRY_INSECURE
|
|
REGISTRY_INSECURE=${REGISTRY_INSECURE:-n}
|
|
|
|
if [[ "$REGISTRY_INSECURE" == "y" ]]; then
|
|
INSECURE_VALUE="true"
|
|
else
|
|
INSECURE_VALUE="false"
|
|
fi
|
|
|
|
# 添加 Registry 到配置
|
|
TMP_REGISTRY=$(jq -n \
|
|
--arg name "$REGISTRY_NAME" \
|
|
--arg url "$REGISTRY_URL" \
|
|
--arg description "$REGISTRY_DESC" \
|
|
--arg username "$REGISTRY_USER" \
|
|
--arg password "$REGISTRY_PASS" \
|
|
--argjson insecure "$INSECURE_VALUE" \
|
|
'{name: $name, url: $url, description: $description, username: $username, password: $password, insecure: $insecure}')
|
|
|
|
jq ".registries += [$TMP_REGISTRY]" "$TMP_FILE" > "${TMP_FILE}.tmp" && mv "${TMP_FILE}.tmp" "$TMP_FILE"
|
|
echo "✅ Registry '$REGISTRY_NAME' 已添加"
|
|
fi
|
|
|
|
echo ""
|
|
|
|
# ===== Clusters 配置 =====
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "☸️ Kubernetes Cluster 配置"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
read -p "是否从 kubeconfig 导入 Cluster? (y/n) [y]: " ADD_CLUSTER
|
|
ADD_CLUSTER=${ADD_CLUSTER:-y}
|
|
|
|
CLUSTER_INDEX=0
|
|
|
|
while [[ "$ADD_CLUSTER" == "y" ]]; do
|
|
echo ""
|
|
echo "--- Cluster $(($CLUSTER_INDEX + 1)) ---"
|
|
|
|
read -p "Cluster 名称 [cluster$(($CLUSTER_INDEX + 1))]: " CLUSTER_NAME
|
|
CLUSTER_NAME=${CLUSTER_NAME:-cluster$(($CLUSTER_INDEX + 1))}
|
|
|
|
read -p "Cluster 描述: " CLUSTER_DESC
|
|
|
|
echo ""
|
|
echo "📂 请选择数据源:"
|
|
echo " 1) 从 kubeconfig 文件提取"
|
|
echo " 2) 手动输入"
|
|
read -p "选择 [1]: " DATA_SOURCE
|
|
DATA_SOURCE=${DATA_SOURCE:-1}
|
|
|
|
if [[ "$DATA_SOURCE" == "1" ]]; then
|
|
# 从 kubeconfig 提取
|
|
read -p "kubeconfig 文件路径 [~/.kube/config]: " KUBECONFIG_PATH
|
|
KUBECONFIG_PATH=${KUBECONFIG_PATH:-~/.kube/config}
|
|
KUBECONFIG_PATH="${KUBECONFIG_PATH/#\~/$HOME}"
|
|
|
|
if [[ ! -f "$KUBECONFIG_PATH" ]]; then
|
|
echo "❌ kubeconfig 文件不存在: $KUBECONFIG_PATH"
|
|
continue
|
|
fi
|
|
|
|
# 列出可用的 contexts
|
|
echo ""
|
|
echo "📋 可用的 contexts:"
|
|
kubectl --kubeconfig="$KUBECONFIG_PATH" config get-contexts
|
|
echo ""
|
|
|
|
read -p "选择 context (留空使用当前 context): " CONTEXT_NAME
|
|
|
|
if [[ -n "$CONTEXT_NAME" ]]; then
|
|
KUBECTL_OPTS="--kubeconfig=$KUBECONFIG_PATH --context=$CONTEXT_NAME"
|
|
else
|
|
KUBECTL_OPTS="--kubeconfig=$KUBECONFIG_PATH"
|
|
fi
|
|
|
|
# 提取数据
|
|
echo "🔍 正在提取 Cluster 配置..."
|
|
|
|
CLUSTER_HOST=$(kubectl $KUBECTL_OPTS config view --raw -o jsonpath='{.clusters[0].cluster.server}')
|
|
CLUSTER_CA=$(kubectl $KUBECTL_OPTS config view --raw -o jsonpath='{.clusters[0].cluster.certificate-authority-data}')
|
|
CLUSTER_CERT=$(kubectl $KUBECTL_OPTS config view --raw -o jsonpath='{.users[0].user.client-certificate-data}')
|
|
CLUSTER_KEY=$(kubectl $KUBECTL_OPTS config view --raw -o jsonpath='{.users[0].user.client-key-data}')
|
|
|
|
echo " ✓ Server: $CLUSTER_HOST"
|
|
echo " ✓ CA Data: ${CLUSTER_CA:0:50}..."
|
|
echo " ✓ Cert Data: ${CLUSTER_CERT:0:50}..."
|
|
echo " ✓ Key Data: ${CLUSTER_KEY:0:50}..."
|
|
|
|
else
|
|
# 手动输入
|
|
read -p "API Server 地址: " CLUSTER_HOST
|
|
|
|
echo "请输入 CA 证书数据 (Base64 编码,多行输入以空行结束):"
|
|
CLUSTER_CA=""
|
|
while IFS= read -r line; do
|
|
[[ -z "$line" ]] && break
|
|
CLUSTER_CA="${CLUSTER_CA}${line}"
|
|
done
|
|
|
|
echo "请输入客户端证书数据 (Base64 编码,多行输入以空行结束):"
|
|
CLUSTER_CERT=""
|
|
while IFS= read -r line; do
|
|
[[ -z "$line" ]] && break
|
|
CLUSTER_CERT="${CLUSTER_CERT}${line}"
|
|
done
|
|
|
|
echo "请输入客户端密钥数据 (Base64 编码,多行输入以空行结束):"
|
|
CLUSTER_KEY=""
|
|
while IFS= read -r line; do
|
|
[[ -z "$line" ]] && break
|
|
CLUSTER_KEY="${CLUSTER_KEY}${line}"
|
|
done
|
|
fi
|
|
|
|
# 添加 Cluster 到配置
|
|
TMP_CLUSTER=$(cat <<JSON
|
|
{
|
|
"name": "$CLUSTER_NAME",
|
|
"host": "$CLUSTER_HOST",
|
|
"description": "$CLUSTER_DESC",
|
|
"caData": "$CLUSTER_CA",
|
|
"certData": "$CLUSTER_CERT",
|
|
"keyData": "$CLUSTER_KEY"
|
|
}
|
|
JSON
|
|
)
|
|
|
|
jq ".clusters += [$TMP_CLUSTER]" "$TMP_FILE" > "${TMP_FILE}.tmp" && mv "${TMP_FILE}.tmp" "$TMP_FILE"
|
|
echo "✅ Cluster '$CLUSTER_NAME' 已添加"
|
|
|
|
CLUSTER_INDEX=$(($CLUSTER_INDEX + 1))
|
|
|
|
read -p "是否继续添加 Cluster? (y/n) [n]: " ADD_CLUSTER
|
|
ADD_CLUSTER=${ADD_CLUSTER:-n}
|
|
done
|
|
|
|
echo ""
|
|
|
|
# ===== 保存配置 =====
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
echo "💾 保存配置"
|
|
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
|
|
|
|
# 格式化 JSON
|
|
jq '.' "$TMP_FILE" > "$OUTPUT_FILE"
|
|
rm "$TMP_FILE"
|
|
|
|
echo "✅ Bootstrap 配置已保存到: $OUTPUT_FILE"
|
|
echo ""
|
|
|
|
# 显示配置摘要
|
|
echo "📊 配置摘要:"
|
|
echo " - 用户数: $(jq '.users | length' "$OUTPUT_FILE")"
|
|
echo " - Registry 数: $(jq '.registries | length' "$OUTPUT_FILE")"
|
|
echo " - Cluster 数: $(jq '.clusters | length' "$OUTPUT_FILE")"
|
|
echo ""
|
|
|
|
echo "🚀 接下来的步骤:"
|
|
echo " 1. 检查配置文件: cat $OUTPUT_FILE"
|
|
echo " 2. 启动应用: make run-mock"
|
|
echo " 3. 验证数据:"
|
|
echo " curl http://localhost:8080/api/v1/registries"
|
|
echo " curl http://localhost:8080/api/v1/clusters"
|
|
echo ""
|
|
|
|
echo "✨ 完成!"
|