refactor: 更新项目结构和文档,移除不再使用的配置文件

- 修改README.md,更新项目特性和目录结构说明
- 重命名基础设施代码目录为tofu,并添加Docker Swarm配置目录
- 移除不再使用的Docker Compose和Traefik配置文件
- 更新Terraform配置,专注于Oracle Cloud支持,移除华为云相关配置
- 清理开发环境变量和示例文件
This commit is contained in:
2025-09-20 16:49:32 +00:00
parent 7eb4a33523
commit 377f176501
45 changed files with 3278 additions and 69 deletions

174
scripts/setup/setup-opentofu.sh Executable file
View File

@@ -0,0 +1,174 @@
#!/bin/bash
# OpenTofu 设置脚本
set -euo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 OpenTofu 是否已安装
check_opentofu() {
log_info "检查 OpenTofu 安装状态..."
if command -v tofu &> /dev/null; then
local version=$(tofu version | head -n1)
log_success "OpenTofu 已安装: $version"
return 0
else
log_error "OpenTofu 未安装"
return 1
fi
}
# 检查配置文件
check_config() {
log_info "检查配置文件..."
local config_file="tofu/environments/dev/terraform.tfvars"
if [[ ! -f "$config_file" ]]; then
log_error "配置文件不存在: $config_file"
log_info "请复制 terraform.tfvars.example 并填入实际配置"
return 1
fi
# 检查是否包含示例值
if grep -q "your_tenancy_id_here\|your_user_id_here\|your:key:fingerprint:here" "$config_file"; then
log_warning "配置文件包含示例值,请填入实际的 Oracle Cloud 配置"
log_info "需要配置以下项目:"
echo " - tenancy_ocid: Oracle Cloud 租户 OCID"
echo " - user_ocid: 用户 OCID"
echo " - fingerprint: API 密钥指纹"
echo " - private_key_path: 私钥文件路径"
echo " - compartment_ocid: 区间 OCID"
return 1
fi
log_success "配置文件检查通过"
return 0
}
# 初始化 OpenTofu
init_opentofu() {
log_info "初始化 OpenTofu..."
cd tofu/environments/dev
# 清理旧的状态文件
if [[ -d ".terraform" ]]; then
log_info "清理旧的 .terraform 目录..."
rm -rf .terraform
fi
# 初始化
if tofu init; then
log_success "OpenTofu 初始化成功"
else
log_error "OpenTofu 初始化失败"
return 1
fi
cd - > /dev/null
}
# 验证配置
validate_config() {
log_info "验证 OpenTofu 配置..."
cd tofu/environments/dev
if tofu validate; then
log_success "配置验证通过"
else
log_error "配置验证失败"
return 1
fi
cd - > /dev/null
}
# 生成计划
plan_infrastructure() {
log_info "生成基础设施计划..."
cd tofu/environments/dev
if tofu plan -var-file="terraform.tfvars" -out=tfplan; then
log_success "计划生成成功"
log_info "计划文件已保存为 tfplan"
else
log_error "计划生成失败"
return 1
fi
cd - > /dev/null
}
# 显示帮助信息
show_help() {
echo "OpenTofu 设置脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " init - 初始化 OpenTofu"
echo " validate - 验证配置"
echo " plan - 生成执行计划"
echo " check - 检查环境和配置"
echo " help - 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 check # 检查环境"
echo " $0 init # 初始化项目"
echo " $0 plan # 生成计划"
}
# 主函数
main() {
case "${1:-help}" in
"check")
check_opentofu
check_config
;;
"init")
check_opentofu || exit 1
check_config || exit 1
init_opentofu
;;
"validate")
validate_config
;;
"plan")
check_opentofu || exit 1
check_config || exit 1
plan_infrastructure
;;
"help"|*)
show_help
;;
esac
}
# 运行主函数
main "$@"

View File

@@ -0,0 +1,228 @@
#!/bin/bash
# Consul 密钥管理脚本
# 用于安全地管理 Oracle Cloud 和其他云服务商的敏感配置
set -euo pipefail
# 配置
CONSUL_ADDR="${CONSUL_ADDR:-http://localhost:8500}"
CONSUL_TOKEN="${CONSUL_TOKEN:-}"
ENVIRONMENT="${ENVIRONMENT:-dev}"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查 Consul 连接
check_consul() {
log_info "检查 Consul 连接..."
if ! curl -s "${CONSUL_ADDR}/v1/status/leader" > /dev/null; then
log_error "无法连接到 Consul: ${CONSUL_ADDR}"
exit 1
fi
log_success "Consul 连接正常"
}
# 设置 Oracle Cloud 配置
set_oracle_config() {
log_info "设置 Oracle Cloud 配置..."
echo "请输入 Oracle Cloud 配置信息:"
read -p "租户 OCID: " tenancy_ocid
read -p "用户 OCID: " user_ocid
read -p "API 密钥指纹: " fingerprint
read -p "私钥文件路径: " private_key_path
read -p "区间 OCID: " compartment_ocid
# 验证私钥文件是否存在
if [[ ! -f "$private_key_path" ]]; then
log_error "私钥文件不存在: $private_key_path"
exit 1
fi
# 读取私钥内容
private_key_content=$(cat "$private_key_path")
# 存储到 Consul
local base_path="config/${ENVIRONMENT}/oracle"
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid" -d "$tenancy_ocid" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid" -d "$user_ocid" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint" -d "$fingerprint" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/private_key" -d "$private_key_content" > /dev/null
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid" -d "$compartment_ocid" > /dev/null
log_success "Oracle Cloud 配置已存储到 Consul"
}
# 获取 Oracle Cloud 配置
get_oracle_config() {
log_info "从 Consul 获取 Oracle Cloud 配置..."
local base_path="config/${ENVIRONMENT}/oracle"
echo "Oracle Cloud 配置:"
echo "租户 OCID: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid?raw" 2>/dev/null || echo "未设置")"
echo "用户 OCID: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid?raw" 2>/dev/null || echo "未设置")"
echo "指纹: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint?raw" 2>/dev/null || echo "未设置")"
echo "区间 OCID: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid?raw" 2>/dev/null || echo "未设置")"
echo "私钥: $(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/private_key?raw" 2>/dev/null | head -1 || echo "未设置")"
}
# 删除 Oracle Cloud 配置
delete_oracle_config() {
log_warning "删除 Oracle Cloud 配置..."
read -p "确定要删除所有 Oracle Cloud 配置吗?(y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
log_info "操作已取消"
return
fi
local base_path="config/${ENVIRONMENT}/oracle"
curl -s -X DELETE "${CONSUL_ADDR}/v1/kv/${base_path}?recurse" > /dev/null
log_success "Oracle Cloud 配置已删除"
}
# 生成 Terraform 变量文件
generate_terraform_vars() {
log_info "生成 Terraform 变量文件..."
local base_path="config/${ENVIRONMENT}/oracle"
local output_file="infrastructure/environments/${ENVIRONMENT}/terraform.tfvars.consul"
# 从 Consul 获取配置
local tenancy_ocid=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid?raw" 2>/dev/null || echo "")
local user_ocid=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid?raw" 2>/dev/null || echo "")
local fingerprint=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint?raw" 2>/dev/null || echo "")
local compartment_ocid=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid?raw" 2>/dev/null || echo "")
if [[ -z "$tenancy_ocid" ]]; then
log_error "Consul 中没有找到 Oracle Cloud 配置"
exit 1
fi
# 创建临时私钥文件
local temp_key_file="/tmp/oci_private_key_${ENVIRONMENT}.pem"
curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/private_key?raw" > "$temp_key_file"
chmod 600 "$temp_key_file"
# 生成 Terraform 变量文件
cat > "$output_file" << EOF
# 从 Consul 生成的 Oracle Cloud 配置
# 生成时间: $(date)
# 环境: ${ENVIRONMENT}
oci_config = {
tenancy_ocid = "$tenancy_ocid"
user_ocid = "$user_ocid"
fingerprint = "$fingerprint"
private_key_path = "$temp_key_file"
region = "ap-seoul-1"
compartment_ocid = "$compartment_ocid"
}
EOF
log_success "Terraform 变量文件已生成: $output_file"
log_warning "私钥文件位置: $temp_key_file"
log_warning "请在使用完毕后删除临时私钥文件"
}
# 清理临时文件
cleanup_temp_files() {
log_info "清理临时文件..."
rm -f /tmp/oci_private_key_*.pem
rm -f infrastructure/environments/*/terraform.tfvars.consul
log_success "临时文件已清理"
}
# 显示帮助信息
show_help() {
cat << EOF
Consul 密钥管理脚本
用法: $0 [选项]
选项:
set-oracle 设置 Oracle Cloud 配置到 Consul
get-oracle 从 Consul 获取 Oracle Cloud 配置
delete-oracle 从 Consul 删除 Oracle Cloud 配置
generate-vars 从 Consul 生成 Terraform 变量文件
cleanup 清理临时文件
help 显示此帮助信息
环境变量:
CONSUL_ADDR Consul 地址 (默认: http://localhost:8500)
CONSUL_TOKEN Consul ACL Token (可选)
ENVIRONMENT 环境名称 (默认: dev)
示例:
# 设置 Oracle Cloud 配置
$0 set-oracle
# 生成 Terraform 变量文件
$0 generate-vars
# 查看配置
$0 get-oracle
# 清理临时文件
$0 cleanup
EOF
}
# 主函数
main() {
case "${1:-help}" in
"set-oracle")
check_consul
set_oracle_config
;;
"get-oracle")
check_consul
get_oracle_config
;;
"delete-oracle")
check_consul
delete_oracle_config
;;
"generate-vars")
check_consul
generate_terraform_vars
;;
"cleanup")
cleanup_temp_files
;;
"help"|*)
show_help
;;
esac
}
main "$@"

View File

@@ -0,0 +1,311 @@
#!/bin/bash
# Terraform Consul Provider 配置脚本
# 用于配置 Terraform 从 Consul 读取敏感配置
set -euo pipefail
ENVIRONMENT="${ENVIRONMENT:-dev}"
CONSUL_ADDR="${CONSUL_ADDR:-http://localhost:8500}"
# 颜色输出
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
# 创建 Terraform Consul Provider 配置
create_consul_provider() {
local tf_dir="infrastructure/environments/${ENVIRONMENT}"
log_info "创建 Terraform Consul Provider 配置..."
cat > "${tf_dir}/consul-provider.tf" << 'EOF'
# Consul Provider 配置
terraform {
required_providers {
consul = {
source = "hashicorp/consul"
version = "~> 2.18"
}
}
}
provider "consul" {
address = var.consul_config.address
token = lookup(var.consul_config, "token", null)
}
# 从 Consul 读取 Oracle Cloud 配置
data "consul_keys" "oracle_config" {
key {
name = "tenancy_ocid"
path = "config/${var.environment}/oracle/tenancy_ocid"
}
key {
name = "user_ocid"
path = "config/${var.environment}/oracle/user_ocid"
}
key {
name = "fingerprint"
path = "config/${var.environment}/oracle/fingerprint"
}
key {
name = "private_key"
path = "config/${var.environment}/oracle/private_key"
}
key {
name = "compartment_ocid"
path = "config/${var.environment}/oracle/compartment_ocid"
}
}
# 创建临时私钥文件
resource "local_file" "oci_private_key" {
content = data.consul_keys.oracle_config.var.private_key
filename = "/tmp/oci_private_key_${var.environment}.pem"
file_permission = "0600"
lifecycle {
ignore_changes = [content]
}
}
# 本地变量,用于构建完整的 OCI 配置
locals {
oci_config_from_consul = {
tenancy_ocid = data.consul_keys.oracle_config.var.tenancy_ocid
user_ocid = data.consul_keys.oracle_config.var.user_ocid
fingerprint = data.consul_keys.oracle_config.var.fingerprint
private_key_path = local_file.oci_private_key.filename
region = var.oci_config.region
compartment_ocid = data.consul_keys.oracle_config.var.compartment_ocid
}
}
EOF
log_success "Consul Provider 配置已创建: ${tf_dir}/consul-provider.tf"
}
# 创建变量定义文件
create_variables() {
local tf_dir="infrastructure/environments/${ENVIRONMENT}"
log_info "更新 Terraform 变量定义..."
cat > "${tf_dir}/variables.tf" << 'EOF'
# 基本变量
variable "environment" {
description = "环境名称"
type = string
}
variable "project_name" {
description = "项目名称"
type = string
}
variable "owner" {
description = "项目所有者"
type = string
}
variable "cloud_providers" {
description = "要启用的云服务商"
type = list(string)
default = []
}
variable "vpc_cidr" {
description = "VPC CIDR 块"
type = string
}
variable "availability_zones" {
description = "可用区列表"
type = list(string)
}
variable "common_tags" {
description = "通用标签"
type = map(string)
default = {}
}
# Consul 配置
variable "consul_config" {
description = "Consul 配置"
type = object({
address = string
token = optional(string)
})
}
# Oracle Cloud 配置(基本信息)
variable "oci_config" {
description = "Oracle Cloud 基本配置"
type = object({
region = string
tenancy_ocid = optional(string, "FROM_CONSUL")
user_ocid = optional(string, "FROM_CONSUL")
fingerprint = optional(string, "FROM_CONSUL")
private_key_path = optional(string, "FROM_CONSUL")
compartment_ocid = optional(string, "FROM_CONSUL")
})
}
# 其他云服务商配置
variable "huawei_config" {
description = "华为云配置"
type = object({
access_key = string
secret_key = string
region = string
project_id = string
})
default = {
access_key = ""
secret_key = ""
region = "cn-north-4"
project_id = ""
}
}
variable "gcp_config" {
description = "Google Cloud 配置"
type = object({
project_id = string
region = string
zone = string
credentials_file = string
})
default = {
project_id = ""
region = "asia-northeast3"
zone = "asia-northeast3-a"
credentials_file = ""
}
}
variable "aws_config" {
description = "AWS 配置"
type = object({
region = string
access_key = string
secret_key = string
})
default = {
region = "ap-northeast-2"
access_key = ""
secret_key = ""
}
}
variable "do_config" {
description = "DigitalOcean 配置"
type = object({
token = string
region = string
})
default = {
token = ""
region = "sgp1"
}
}
EOF
log_success "变量定义已更新: ${tf_dir}/variables.tf"
}
# 创建示例 main.tf
create_main_tf() {
local tf_dir="infrastructure/environments/${ENVIRONMENT}"
log_info "创建示例 main.tf..."
cat > "${tf_dir}/main.tf" << 'EOF'
# 主要 Terraform 配置文件
terraform {
required_version = ">= 1.0"
required_providers {
oci = {
source = "oracle/oci"
version = "~> 5.0"
}
}
}
# Oracle Cloud Provider
provider "oci" {
tenancy_ocid = local.oci_config_from_consul.tenancy_ocid
user_ocid = local.oci_config_from_consul.user_ocid
fingerprint = local.oci_config_from_consul.fingerprint
private_key_path = local.oci_config_from_consul.private_key_path
region = local.oci_config_from_consul.region
}
# 示例:创建 VCN
resource "oci_core_vcn" "main" {
count = contains(var.cloud_providers, "oracle") ? 1 : 0
compartment_id = local.oci_config_from_consul.compartment_ocid
cidr_block = var.vpc_cidr
display_name = "${var.project_name}-${var.environment}-vcn"
freeform_tags = var.common_tags
}
# 输出
output "vcn_id" {
description = "VCN ID"
value = try(oci_core_vcn.main[0].id, null)
}
output "oci_config_source" {
description = "OCI 配置来源"
value = "consul"
}
EOF
log_success "示例 main.tf 已创建: ${tf_dir}/main.tf"
}
# 主函数
main() {
case "${1:-help}" in
"setup")
create_consul_provider
create_variables
create_main_tf
;;
"help"|*)
cat << EOF
Terraform Consul Provider 配置脚本
用法: $0 [选项]
选项:
setup 创建 Terraform Consul Provider 配置
help 显示此帮助信息
环境变量:
ENVIRONMENT 环境名称 (默认: dev)
CONSUL_ADDR Consul 地址 (默认: http://localhost:8500)
EOF
;;
esac
}
main "$@"

View File

@@ -0,0 +1,128 @@
#!/bin/bash
# 简化版 OpenTofu 密钥上传脚本
set -euo pipefail
# 配置
CONSUL_ADDR="${CONSUL_ADDR:-http://master:8500}"
ENVIRONMENT="${ENVIRONMENT:-dev}"
TFVARS_FILE="tofu/environments/${ENVIRONMENT}/terraform.tfvars"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1"; }
log_error() { echo -e "${RED}[ERROR]${NC} $1"; }
# 检查 Consul 连接
check_consul() {
log_info "检查 Consul 连接..."
if ! curl -s "${CONSUL_ADDR}/v1/status/leader" > /dev/null; then
log_error "无法连接到 Consul: ${CONSUL_ADDR}"
exit 1
fi
log_success "Consul 连接正常"
}
# 上传配置
upload_configs() {
local uploaded_count=0
log_info "开始解析并上传配置..."
# 直接解析 tfvars 文件
while IFS= read -r line; do
# 跳过注释和空行
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# 匹配变量赋值
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\"([^\"]*)\"|^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*([^[:space:]#]+) ]]; then
local var_name="${BASH_REMATCH[1]:-${BASH_REMATCH[3]}}"
local var_value="${BASH_REMATCH[2]:-${BASH_REMATCH[4]}}"
# 跳过空值
if [[ -z "$var_value" || "$var_value" == "null" ]]; then
continue
fi
# 确定配置分类和路径
local consul_path=""
if [[ "$var_name" =~ ^oci_ ]]; then
consul_path="config/${ENVIRONMENT}/oracle/${var_name#oci_}"
elif [[ "$var_name" =~ ^huawei_ ]]; then
consul_path="config/${ENVIRONMENT}/huawei/${var_name#huawei_}"
elif [[ "$var_name" =~ ^aws_ ]]; then
consul_path="config/${ENVIRONMENT}/aws/${var_name#aws_}"
elif [[ "$var_name" =~ ^do_ ]]; then
consul_path="config/${ENVIRONMENT}/digitalocean/${var_name#do_}"
elif [[ "$var_name" =~ ^gcp_ ]]; then
consul_path="config/${ENVIRONMENT}/gcp/${var_name#gcp_}"
else
consul_path="config/${ENVIRONMENT}/general/${var_name}"
fi
# 上传到 Consul
if curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${consul_path}" -d "$var_value" > /dev/null; then
log_info "上传: ${consul_path}"
((uploaded_count++))
else
log_error "上传失败: ${consul_path}"
fi
fi
done < "$TFVARS_FILE"
log_success "总共上传了 $uploaded_count 个配置项到 Consul"
}
# 列出配置
list_configs() {
log_info "列出 Consul 中的配置..."
local keys=$(curl -s "${CONSUL_ADDR}/v1/kv/config/${ENVIRONMENT}/?keys" | jq -r '.[]' 2>/dev/null || echo "")
if [[ -z "$keys" ]]; then
log_error "没有找到配置"
return
fi
echo "=== 环境 ${ENVIRONMENT} 的配置 ==="
echo "$keys" | while read -r key; do
local value=$(curl -s "${CONSUL_ADDR}/v1/kv/${key}?raw" 2>/dev/null || echo "无法读取")
# 隐藏敏感信息
if [[ "$key" =~ (secret|key|token|password|ocid) ]]; then
echo "$key: [已隐藏]"
else
echo "$key: $value"
fi
done
}
# 主函数
main() {
if [[ ! -f "$TFVARS_FILE" ]]; then
log_error "找不到配置文件: $TFVARS_FILE"
exit 1
fi
check_consul
case "${1:-upload}" in
"upload")
upload_configs
;;
"list")
list_configs
;;
*)
echo "用法: $0 [upload|list]"
;;
esac
}
main "$@"

View File

@@ -0,0 +1,495 @@
#!/bin/bash
# OpenTofu 密钥上传脚本
# 用于将 terraform.tfvars 中的敏感配置批量上传到 Consul
set -euo pipefail
# 配置
CONSUL_ADDR="${CONSUL_ADDR:-http://master:8500}"
CONSUL_TOKEN="${CONSUL_TOKEN:-}"
ENVIRONMENT="${ENVIRONMENT:-dev}"
TOFU_DIR="${TOFU_DIR:-tofu/environments/${ENVIRONMENT}}"
TFVARS_FILE="${TFVARS_FILE:-${TOFU_DIR}/terraform.tfvars}"
# 颜色输出
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 日志函数
log_info() {
echo -e "${BLUE}[INFO]${NC} $1"
}
log_success() {
echo -e "${GREEN}[SUCCESS]${NC} $1"
}
log_warning() {
echo -e "${YELLOW}[WARNING]${NC} $1"
}
log_error() {
echo -e "${RED}[ERROR]${NC} $1"
}
# 检查依赖
check_dependencies() {
local deps=("curl" "jq")
for dep in "${deps[@]}"; do
if ! command -v "$dep" &> /dev/null; then
log_error "缺少依赖: $dep"
exit 1
fi
done
}
# 检查 Consul 连接
check_consul() {
log_info "检查 Consul 连接..."
if ! curl -s "${CONSUL_ADDR}/v1/status/leader" > /dev/null; then
log_error "无法连接到 Consul: ${CONSUL_ADDR}"
exit 1
fi
log_success "Consul 连接正常"
}
# 检查 tfvars 文件
check_tfvars_file() {
if [[ ! -f "$TFVARS_FILE" ]]; then
log_error "找不到 terraform.tfvars 文件: $TFVARS_FILE"
exit 1
fi
log_info "找到配置文件: $TFVARS_FILE"
}
# 解析 HCL 配置并转换为 JSON
parse_hcl_to_json() {
local tfvars_file="$1"
local temp_tf_file="/tmp/temp_config.tf"
local temp_json_file="/tmp/temp_config.json"
# 创建临时 .tf 文件,将变量赋值转换为输出
log_info "解析 HCL 配置..."
# 读取 tfvars 文件并转换为 output 格式
cat > "$temp_tf_file" << 'EOF'
# 临时配置文件,用于解析 tfvars
EOF
# 解析每个配置块
while IFS= read -r line; do
# 跳过注释和空行
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# 提取变量名和值
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*(.+)$ ]]; then
local var_name="${BASH_REMATCH[1]}"
local var_value="${BASH_REMATCH[2]}"
echo "output \"$var_name\" {" >> "$temp_tf_file"
echo " value = $var_value" >> "$temp_tf_file"
echo "}" >> "$temp_tf_file"
fi
done < "$tfvars_file"
# 使用 terraform 解析配置
if command -v terraform &> /dev/null; then
cd "$(dirname "$temp_tf_file")"
terraform init -backend=false > /dev/null 2>&1 || true
terraform output -json > "$temp_json_file" 2>/dev/null || {
log_warning "无法使用 terraform 解析,尝试手动解析..."
manual_parse_tfvars "$tfvars_file" "$temp_json_file"
}
else
log_warning "未找到 terraform使用手动解析..."
manual_parse_tfvars "$tfvars_file" "$temp_json_file"
fi
echo "$temp_json_file"
}
# 手动解析 tfvars 文件
manual_parse_tfvars() {
local tfvars_file="$1"
local output_file="$2"
log_info "手动解析 tfvars 文件..."
# 创建基础 JSON 结构
echo "{" > "$output_file"
local first_item=true
local in_block=false
local block_name=""
local block_content=""
while IFS= read -r line; do
# 跳过注释和空行
if [[ "$line" =~ ^[[:space:]]*# ]] || [[ -z "${line// }" ]]; then
continue
fi
# 检测配置块开始
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\{[[:space:]]*$ ]]; then
block_name="${BASH_REMATCH[1]}"
in_block=true
block_content=""
continue
fi
# 检测配置块结束
if [[ "$in_block" == true && "$line" =~ ^[[:space:]]*\}[[:space:]]*$ ]]; then
if [[ "$first_item" == false ]]; then
echo "," >> "$output_file"
fi
echo " \"$block_name\": {" >> "$output_file"
echo "$block_content" >> "$output_file"
echo " }" >> "$output_file"
first_item=false
in_block=false
continue
fi
# 处理块内容
if [[ "$in_block" == true ]]; then
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\"([^\"]*)\"|^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*([^[:space:]]+) ]]; then
local key="${BASH_REMATCH[1]:-${BASH_REMATCH[3]}}"
local value="${BASH_REMATCH[2]:-${BASH_REMATCH[4]}}"
if [[ -n "$block_content" ]]; then
block_content+=","
fi
block_content+="\n \"$key\": \"$value\""
fi
continue
fi
# 处理简单变量
if [[ "$line" =~ ^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*\"([^\"]*)\"|^[[:space:]]*([a-zA-Z_][a-zA-Z0-9_]*)[[:space:]]*=[[:space:]]*([^[:space:]]+) ]]; then
local var_name="${BASH_REMATCH[1]:-${BASH_REMATCH[3]}}"
local var_value="${BASH_REMATCH[2]:-${BASH_REMATCH[4]}}"
if [[ "$first_item" == false ]]; then
echo "," >> "$output_file"
fi
echo " \"$var_name\": \"$var_value\"" >> "$output_file"
first_item=false
fi
done < "$tfvars_file"
echo "}" >> "$output_file"
}
# 上传配置到 Consul
upload_config_to_consul() {
local config_file="$1"
local uploaded_count=0
log_info "开始上传配置到 Consul..."
# 读取 JSON 配置
if [[ ! -f "$config_file" ]]; then
log_error "配置文件不存在: $config_file"
return 1
fi
# 上传 Oracle Cloud 配置
local oci_tenancy=$(jq -r '.oci_tenancy_ocid // empty' "$config_file")
local oci_user=$(jq -r '.oci_user_ocid // empty' "$config_file")
local oci_fingerprint=$(jq -r '.oci_fingerprint // empty' "$config_file")
local oci_private_key_path=$(jq -r '.oci_private_key_path // empty' "$config_file")
local oci_compartment=$(jq -r '.oci_compartment_ocid // empty' "$config_file")
local oci_region=$(jq -r '.oci_region // empty' "$config_file")
if [[ -n "$oci_tenancy" && "$oci_tenancy" != "null" && "$oci_tenancy" != "" ]]; then
=======
# 上传配置到 Consul
upload_config_to_consul() {
local config_file="$1"
local uploaded_count=0
log_info "开始上传配置到 Consul..."
# 读取 JSON 配置
if [[ ! -f "$config_file" ]]; then
log_error "配置文件不存在: $config_file"
return 1
fi
# 上传 Oracle Cloud 配置
local oci_tenancy=$(jq -r '.oci_tenancy_ocid // empty' "$config_file")
local oci_user=$(jq -r '.oci_user_ocid // empty' "$config_file")
local oci_fingerprint=$(jq -r '.oci_fingerprint // empty' "$config_file")
local oci_private_key_path=$(jq -r '.oci_private_key_path // empty' "$config_file")
local oci_compartment=$(jq -r '.oci_compartment_ocid // empty' "$config_file")
local oci_region=$(jq -r '.oci_region // empty' "$config_file")
if [[ -n "$oci_tenancy" && "$oci_tenancy" != "null" && "$oci_tenancy" != "" ]]; then
log_info "上传 Oracle Cloud 配置..."
local base_path="config/${ENVIRONMENT}/oracle"
local tenancy_ocid=$(jq -r '.oci_config.tenancy_ocid // empty' "$config_file")
local user_ocid=$(jq -r '.oci_config.user_ocid // empty' "$config_file")
local fingerprint=$(jq -r '.oci_config.fingerprint // empty' "$config_file")
local private_key_path=$(jq -r '.oci_config.private_key_path // empty' "$config_file")
local compartment_ocid=$(jq -r '.oci_config.compartment_ocid // empty' "$config_file")
local region=$(jq -r '.oci_config.region // "ap-seoul-1"' "$config_file")
# 上传非空配置
[[ -n "$tenancy_ocid" && "$tenancy_ocid" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/tenancy_ocid" -d "$tenancy_ocid" > /dev/null
((uploaded_count++))
}
[[ -n "$user_ocid" && "$user_ocid" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/user_ocid" -d "$user_ocid" > /dev/null
((uploaded_count++))
}
[[ -n "$fingerprint" && "$fingerprint" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/fingerprint" -d "$fingerprint" > /dev/null
((uploaded_count++))
}
[[ -n "$compartment_ocid" && "$compartment_ocid" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/compartment_ocid" -d "$compartment_ocid" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
# 上传私钥文件内容
if [[ -n "$private_key_path" && "$private_key_path" != "null" && -f "$private_key_path" ]]; then
local private_key_content=$(cat "$private_key_path")
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/private_key" -d "$private_key_content" > /dev/null
((uploaded_count++))
fi
log_success "Oracle Cloud 配置已上传"
fi
# 上传华为云配置
if jq -e '.huawei_config' "$config_file" > /dev/null 2>&1; then
log_info "上传华为云配置..."
local base_path="config/${ENVIRONMENT}/huawei"
local access_key=$(jq -r '.huawei_config.access_key // empty' "$config_file")
local secret_key=$(jq -r '.huawei_config.secret_key // empty' "$config_file")
local region=$(jq -r '.huawei_config.region // "cn-north-4"' "$config_file")
local project_id=$(jq -r '.huawei_config.project_id // empty' "$config_file")
[[ -n "$access_key" && "$access_key" != "null" && "$access_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/access_key" -d "$access_key" > /dev/null
((uploaded_count++))
}
[[ -n "$secret_key" && "$secret_key" != "null" && "$secret_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/secret_key" -d "$secret_key" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
[[ -n "$project_id" && "$project_id" != "null" && "$project_id" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/project_id" -d "$project_id" > /dev/null
((uploaded_count++))
}
log_success "华为云配置已上传"
fi
# 上传 AWS 配置
if jq -e '.aws_config' "$config_file" > /dev/null 2>&1; then
log_info "上传 AWS 配置..."
local base_path="config/${ENVIRONMENT}/aws"
local access_key=$(jq -r '.aws_config.access_key // empty' "$config_file")
local secret_key=$(jq -r '.aws_config.secret_key // empty' "$config_file")
local region=$(jq -r '.aws_config.region // "ap-northeast-2"' "$config_file")
[[ -n "$access_key" && "$access_key" != "null" && "$access_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/access_key" -d "$access_key" > /dev/null
((uploaded_count++))
}
[[ -n "$secret_key" && "$secret_key" != "null" && "$secret_key" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/secret_key" -d "$secret_key" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
log_success "AWS 配置已上传"
fi
# 上传 DigitalOcean 配置
if jq -e '.do_config' "$config_file" > /dev/null 2>&1; then
log_info "上传 DigitalOcean 配置..."
local base_path="config/${ENVIRONMENT}/digitalocean"
local token=$(jq -r '.do_config.token // empty' "$config_file")
local region=$(jq -r '.do_config.region // "sgp1"' "$config_file")
[[ -n "$token" && "$token" != "null" && "$token" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/token" -d "$token" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
log_success "DigitalOcean 配置已上传"
fi
# 上传 Google Cloud 配置
if jq -e '.gcp_config' "$config_file" > /dev/null 2>&1; then
log_info "上传 Google Cloud 配置..."
local base_path="config/${ENVIRONMENT}/gcp"
local project_id=$(jq -r '.gcp_config.project_id // empty' "$config_file")
local region=$(jq -r '.gcp_config.region // "asia-northeast3"' "$config_file")
local zone=$(jq -r '.gcp_config.zone // "asia-northeast3-a"' "$config_file")
local credentials_file=$(jq -r '.gcp_config.credentials_file // empty' "$config_file")
[[ -n "$project_id" && "$project_id" != "null" && "$project_id" != "" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/project_id" -d "$project_id" > /dev/null
((uploaded_count++))
}
[[ -n "$region" && "$region" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/region" -d "$region" > /dev/null
((uploaded_count++))
}
[[ -n "$zone" && "$zone" != "null" ]] && {
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/zone" -d "$zone" > /dev/null
((uploaded_count++))
}
# 上传凭证文件内容
if [[ -n "$credentials_file" && "$credentials_file" != "null" && -f "$credentials_file" ]]; then
local credentials_content=$(cat "$credentials_file")
curl -s -X PUT "${CONSUL_ADDR}/v1/kv/${base_path}/credentials" -d "$credentials_content" > /dev/null
((uploaded_count++))
fi
log_success "Google Cloud 配置已上传"
fi
log_success "总共上传了 $uploaded_count 个配置项到 Consul"
}
# 列出 Consul 中的配置
list_consul_configs() {
log_info "列出 Consul 中的配置..."
local base_path="config/${ENVIRONMENT}"
echo "=== Consul 中的配置 ==="
# 获取所有配置键
local keys=$(curl -s "${CONSUL_ADDR}/v1/kv/${base_path}/?keys" | jq -r '.[]' 2>/dev/null || echo "")
if [[ -z "$keys" ]]; then
log_warning "Consul 中没有找到配置"
return
fi
echo "$keys" | while read -r key; do
local value=$(curl -s "${CONSUL_ADDR}/v1/kv/${key}?raw" 2>/dev/null || echo "无法读取")
# 隐藏敏感信息
if [[ "$key" =~ (secret|key|token|password) ]]; then
echo "$key: [已隐藏]"
else
echo "$key: $value"
fi
done
}
# 清理 Consul 配置
cleanup_consul_configs() {
log_warning "清理 Consul 配置..."
read -p "确定要删除环境 '$ENVIRONMENT' 的所有配置吗?(y/N): " confirm
if [[ "$confirm" != "y" && "$confirm" != "Y" ]]; then
log_info "操作已取消"
return
fi
local base_path="config/${ENVIRONMENT}"
curl -s -X DELETE "${CONSUL_ADDR}/v1/kv/${base_path}?recurse" > /dev/null
log_success "环境 '$ENVIRONMENT' 的配置已清理"
}
# 显示帮助信息
show_help() {
cat << EOF
OpenTofu 密钥上传脚本
用法: $0 [选项]
选项:
upload 上传 terraform.tfvars 中的配置到 Consul
list 列出 Consul 中的配置
cleanup 清理 Consul 中的配置
help 显示此帮助信息
环境变量:
CONSUL_ADDR Consul 地址 (默认: http://localhost:8500)
CONSUL_TOKEN Consul ACL Token (可选)
ENVIRONMENT 环境名称 (默认: dev)
TOFU_DIR OpenTofu 目录 (默认: tofu/environments/\${ENVIRONMENT})
TFVARS_FILE 变量文件路径 (默认: \${TOFU_DIR}/terraform.tfvars)
示例:
# 上传配置到 Consul
$0 upload
# 列出 Consul 中的配置
$0 list
# 清理配置
$0 cleanup
# 指定不同环境
ENVIRONMENT=production $0 upload
EOF
}
# 主函数
main() {
check_dependencies
case "${1:-help}" in
"upload")
check_consul
check_tfvars_file
log_info "解析配置文件: $TFVARS_FILE"
local config_json=$(manual_parse_tfvars "$TFVARS_FILE" "/tmp/parsed_config.json")
upload_config_to_consul "/tmp/parsed_config.json"
# 清理临时文件
rm -f /tmp/parsed_config.json /tmp/temp_config.tf
;;
"list")
check_consul
list_consul_configs
;;
"cleanup")
check_consul
cleanup_consul_configs
;;
"help"|*)
show_help
;;
esac
}
main "$@"