Files
ocdp-go/backend/cmd/api/main.go
mangomqy c5e51ed069 ocdp v1
2025-11-13 02:54:06 +00:00

310 lines
11 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// @title OCDP Backend API
// @version 1.0
// @description OCDP (Open Cloud Development Platform) Backend API
// @description
// @description RESTful API for managing Kubernetes clusters, OCI registries, and Helm deployments.
//
// @contact.name API Support
// @contact.email support@ocdp.io
//
// @license.name Apache 2.0
// @license.url http://www.apache.org/licenses/LICENSE-2.0.html
//
// @host localhost:8080
// @BasePath /api/v1
//
// @schemes http https
//
// @securityDefinitions.apikey BearerAuth
// @in header
// @name Authorization
// @description Type "Bearer" followed by a space and JWT token.
package main
import (
"context"
"fmt"
"log"
"net/http"
"os"
"time"
"github.com/gorilla/mux"
"github.com/ocdp/cluster-service/internal/adapter/input/http/rest"
"github.com/ocdp/cluster-service/internal/adapter/output"
"github.com/ocdp/cluster-service/internal/bootstrap"
"github.com/ocdp/cluster-service/internal/domain/service"
"github.com/ocdp/cluster-service/internal/pkg/crypto"
"github.com/ocdp/cluster-service/internal/pkg/jwt"
"github.com/ocdp/cluster-service/internal/pkg/password"
)
func main() {
log.Println("🚀 Starting OCDP Backend (Hexagonal Architecture)")
// ===== 1. 读取配置 =====
config := loadConfig()
log.Printf("📝 Configuration: mode=%s, port=%s", config.AdapterMode, config.Port)
// ===== 2. 创建加密器(用于敏感数据加密存储) =====
encryptor := crypto.NewAESEncryptor(config.EncryptionKey)
log.Println("✅ Encryption enabled for sensitive data")
// ===== 3. 创建 Output Adapters通过工厂 =====
factory := output.NewAdapterFactory(
output.AdapterMode(config.AdapterMode),
encryptor,
config.DatabaseURL,
)
repos, err := factory.CreateAllRepositories()
if err != nil {
log.Fatalf("❌ Failed to create adapters: %v", err)
}
log.Printf("✅ Output Adapters initialized (mode: %s)", config.AdapterMode)
// ===== 4. 创建工具包实例 =====
passwordHasher := password.NewHasher()
tokenGenerator := jwt.NewJWTManager(config.JWTSecret)
log.Println("✅ Utilities initialized")
// ===== 5. 创建 Domain Services =====
authService := service.NewAuthService(
repos.UserRepo,
passwordHasher,
tokenGenerator,
)
clusterService := service.NewClusterService(
repos.ClusterRepo,
)
registryService := service.NewRegistryService(
repos.RegistryRepo,
repos.OCIClient,
)
artifactService := service.NewArtifactService(
repos.RegistryRepo,
repos.OCIClient,
)
instanceService := service.NewInstanceService(
repos.InstanceRepo,
repos.ClusterRepo,
repos.RegistryRepo,
repos.HelmClient,
repos.OCIClient,
repos.EntryClient,
)
monitoringService := service.NewMonitoringService(
repos.ClusterRepo,
repos.MetricsClient,
)
log.Println("✅ Domain Services initialized")
// ===== 6. 加载并执行 Bootstrap 预注入 =====
bootstrapConfig, err := bootstrap.LoadBootstrapConfig()
if err != nil {
log.Printf("⚠️ Warning: Failed to load bootstrap config: %v", err)
// 使用默认配置
bootstrapConfig = bootstrap.GetDefaultBootstrapConfig()
}
seeder := bootstrap.NewSeeder(repos, passwordHasher, bootstrapConfig)
if err := seeder.SeedAll(context.Background()); err != nil {
log.Printf("⚠️ Warning: Failed to seed data: %v", err)
}
// ===== 7. 创建 Input Adapters (REST Handlers) =====
authHandler := rest.NewAuthHandler(authService)
clusterHandler := rest.NewClusterHandler(clusterService)
registryHandler := rest.NewRegistryHandler(registryService)
artifactHandler := rest.NewArtifactHandler(artifactService)
instanceHandler := rest.NewInstanceHandler(instanceService)
monitoringHandler := rest.NewMonitoringHandler(monitoringService)
swaggerHandler := rest.NewSwaggerHandler()
log.Println("✅ Input Adapters (REST handlers) initialized")
// ===== 8. 设置路由 =====
router := setupRouter(
authHandler,
clusterHandler,
registryHandler,
artifactHandler,
instanceHandler,
monitoringHandler,
swaggerHandler,
)
// ===== 9. 启动服务器 =====
addr := fmt.Sprintf(":%s", config.Port)
log.Printf("🌐 Server starting on %s", addr)
log.Println("")
log.Println("📍 Available endpoints:")
log.Printf(" - REST API: http://localhost:%s/api/v1", config.Port)
log.Printf(" - Swagger UI: http://localhost:%s/api/docs", config.Port)
log.Printf(" - OpenAPI Spec: http://localhost:%s/api/docs/openapi.yaml", config.Port)
log.Printf(" - Health: http://localhost:%s/health", config.Port)
log.Println("")
log.Println("✨ Press Ctrl+C to stop")
log.Println("")
if err := http.ListenAndServe(addr, router); err != nil {
log.Fatalf("❌ Server failed: %v", err)
}
}
// Config 应用配置
type Config struct {
AdapterMode string
Port string
JWTSecret string
EncryptionKey string
DatabaseURL string
}
// loadConfig 加载配置
func loadConfig() *Config {
return &Config{
AdapterMode: getEnv("ADAPTER_MODE", ""), // 默认为空字符串(真实模式)
Port: getEnv("PORT", "8080"),
JWTSecret: getEnv("JWT_SECRET", "your-secret-key-change-in-production"),
EncryptionKey: getEnv("ENCRYPTION_KEY", "default-encryption-key-change-in-production"),
DatabaseURL: getEnv("DATABASE_URL", ""),
}
}
// getEnv 获取环境变量,如果不存在则返回默认值
func getEnv(key, defaultValue string) string {
value := os.Getenv(key)
if value == "" {
return defaultValue
}
return value
}
// setupRouter 设置路由
func setupRouter(
authHandler *rest.AuthHandler,
clusterHandler *rest.ClusterHandler,
registryHandler *rest.RegistryHandler,
artifactHandler *rest.ArtifactHandler,
instanceHandler *rest.InstanceHandler,
monitoringHandler *rest.MonitoringHandler,
swaggerHandler *rest.SwaggerHandler,
) *mux.Router {
router := mux.NewRouter().StrictSlash(true)
// 全局中间件
router.Use(loggingMiddleware)
router.Use(corsMiddleware)
// 健康检查
router.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"status":"healthy"}`))
})
// ===== Swagger UI =====
router.HandleFunc("/api/docs", swaggerHandler.ServeSwaggerUI).Methods(http.MethodGet)
router.HandleFunc("/api/docs/assets/swagger-ui.css", swaggerHandler.ServeSwaggerCSS).Methods(http.MethodGet)
router.HandleFunc("/api/docs/assets/swagger-ui-bundle.js", swaggerHandler.ServeSwaggerBundle).Methods(http.MethodGet)
router.HandleFunc("/api/docs/assets/swagger-ui-standalone-preset.js", swaggerHandler.ServeSwaggerStandalonePreset).Methods(http.MethodGet)
router.HandleFunc("/api/docs/openapi.yaml", swaggerHandler.ServeOpenAPISpec).Methods(http.MethodGet)
// API v1
api := router.PathPrefix("/api/v1").Subrouter()
// ===== 认证路由 =====
api.HandleFunc("/auth/register", authHandler.Register)
api.HandleFunc("/auth/login", authHandler.Login)
api.HandleFunc("/auth/refresh", authHandler.RefreshToken)
// ===== 集群路由 =====
api.HandleFunc("/clusters", clusterHandler.CreateCluster).Methods(http.MethodPost)
api.HandleFunc("/clusters", clusterHandler.GetAllClusters).Methods(http.MethodGet)
api.HandleFunc("/clusters/{cluster_id}", clusterHandler.GetCluster).Methods(http.MethodGet)
api.HandleFunc("/clusters/{cluster_id}", clusterHandler.UpdateCluster).Methods(http.MethodPut)
api.HandleFunc("/clusters/{cluster_id}", clusterHandler.DeleteCluster).Methods(http.MethodDelete)
api.HandleFunc("/clusters/{cluster_id}/health", clusterHandler.GetClusterHealth).Methods(http.MethodGet)
// ===== Registry 路由 =====
api.HandleFunc("/registries", registryHandler.CreateRegistry).Methods(http.MethodPost)
api.HandleFunc("/registries", registryHandler.GetAllRegistries).Methods(http.MethodGet)
api.HandleFunc("/registries/{registry_id}", registryHandler.GetRegistry).Methods(http.MethodGet)
api.HandleFunc("/registries/{registry_id}", registryHandler.UpdateRegistry).Methods(http.MethodPut)
api.HandleFunc("/registries/{registry_id}", registryHandler.DeleteRegistry).Methods(http.MethodDelete)
api.HandleFunc("/registries/{registry_id}/health", registryHandler.GetRegistryHealth).Methods(http.MethodGet)
// ===== Artifact 路由 =====
api.HandleFunc("/registries/{registry_id}/repositories", artifactHandler.ListRepositories).Methods(http.MethodGet)
api.HandleFunc("/registries/{registry_id}/repositories/{repository_name:.+}/artifacts", artifactHandler.ListArtifacts).Methods(http.MethodGet)
api.HandleFunc("/registries/{registry_id}/repositories/{repository_name:.+}/artifacts/{reference}", artifactHandler.GetArtifact).Methods(http.MethodGet)
api.HandleFunc("/registries/{registry_id}/repositories/{repository_name:.+}/artifacts/{reference}/values-schema", artifactHandler.GetArtifactValuesSchema).Methods(http.MethodGet)
// ===== Instance 路由 =====
api.HandleFunc("/clusters/{cluster_id}/instances", instanceHandler.CreateInstance).Methods(http.MethodPost)
api.HandleFunc("/clusters/{cluster_id}/instances", instanceHandler.ListInstances).Methods(http.MethodGet)
api.HandleFunc("/clusters/{cluster_id}/instances/{instance_id}", instanceHandler.GetInstance).Methods(http.MethodGet)
api.HandleFunc("/clusters/{cluster_id}/instances/{instance_id}", instanceHandler.UpdateInstance).Methods(http.MethodPut)
api.HandleFunc("/clusters/{cluster_id}/instances/{instance_id}", instanceHandler.DeleteInstance).Methods(http.MethodDelete)
api.HandleFunc("/clusters/{cluster_id}/instances/{instance_id}/entries", instanceHandler.ListInstanceEntries).Methods(http.MethodGet)
// ===== Monitoring 路由 =====
api.HandleFunc("/monitoring/clusters", monitoringHandler.ListClusterMonitoring).Methods(http.MethodGet)
api.HandleFunc("/monitoring/clusters/{cluster_id}", monitoringHandler.GetClusterMonitoring).Methods(http.MethodGet)
api.HandleFunc("/monitoring/clusters/{cluster_id}/nodes", monitoringHandler.GetNodeMetrics).Methods(http.MethodGet)
api.HandleFunc("/monitoring/summary", monitoringHandler.GetMonitoringSummary).Methods(http.MethodGet)
// 处理 MethodNotAllowed 错误OPTIONS 请求会触发)
router.MethodNotAllowedHandler = http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
if r.Method == http.MethodOptions {
// CORS 预检已在中间件处理,这里直接返回
w.WriteHeader(http.StatusNoContent)
return
}
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
})
return router
}
// loggingMiddleware 日志中间件
func loggingMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
next.ServeHTTP(w, r)
log.Printf("%s %s %s %v", r.Method, r.RequestURI, r.RemoteAddr, time.Since(start))
})
}
// corsMiddleware CORS 中间件
func corsMiddleware(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 设置 CORS 头
origin := r.Header.Get("Origin")
if origin == "" {
origin = "*"
}
w.Header().Set("Access-Control-Allow-Origin", origin)
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization, X-Requested-With")
w.Header().Set("Access-Control-Allow-Credentials", "true")
w.Header().Set("Access-Control-Max-Age", "86400")
// 处理 OPTIONS 预检请求
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}