Files
ocdp-go/backend/internal/adapter/output/factory.go
Ivan087 7f238a3168 refactor: full-stack restructure with multi-tenancy, workspace management, and K8s diagnostics
- 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
2026-05-12 16:15:14 +08:00

292 lines
8.7 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.

package output
import (
"fmt"
helmMock "github.com/ocdp/cluster-service/internal/adapter/output/helm/mock"
helmReal "github.com/ocdp/cluster-service/internal/adapter/output/helm/real"
"github.com/ocdp/cluster-service/internal/adapter/output/k8s"
ociMock "github.com/ocdp/cluster-service/internal/adapter/output/oci/mock"
ociReal "github.com/ocdp/cluster-service/internal/adapter/output/oci/real"
"github.com/ocdp/cluster-service/internal/adapter/output/persistence/mock"
"github.com/ocdp/cluster-service/internal/adapter/output/persistence/postgres"
"github.com/ocdp/cluster-service/internal/domain/repository"
"github.com/ocdp/cluster-service/internal/pkg/crypto"
)
// AdapterMode 适配器模式
type AdapterMode string
const (
ModeMock AdapterMode = "mock" // Mock 模式(内存存储,用于开发调试)
// 默认模式:连接真实 PostgreSQL 和服务(任何非 "mock" 的值都是默认模式)
)
// AdapterFactory 适配器工厂
// 用于创建所有 Output Adapters支持 Mock 和真实实现切换
type AdapterFactory struct {
mode AdapterMode
encryptor crypto.Encryptor // 加密器(用于敏感数据加密)
// 数据库连接字符串(非 Mock 模式需要)
dbConnString string
// 数据库连接(非 Mock 模式)
db *postgres.DB
}
// NewAdapterFactory 创建适配器工厂
func NewAdapterFactory(mode AdapterMode, encryptor crypto.Encryptor, dbConnString string) *AdapterFactory {
return &AdapterFactory{
mode: mode,
encryptor: encryptor,
dbConnString: dbConnString,
}
}
// CreateUserRepository 创建用户仓储
func (f *AdapterFactory) CreateUserRepository() (repository.UserRepository, error) {
if f.mode == ModeMock {
return mock.NewUserRepositoryMock(), nil
}
// 默认真实实现PostgreSQL
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewUserRepository(f.db), nil
}
// CreateClusterRepository 创建集群仓储
func (f *AdapterFactory) CreateClusterRepository() (repository.ClusterRepository, error) {
if f.mode == ModeMock {
return mock.NewClusterRepositoryMock(f.encryptor), nil
}
// 默认真实实现PostgreSQL
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewClusterRepository(f.db, f.encryptor), nil
}
// CreateRegistryRepository 创建 Registry 仓储
func (f *AdapterFactory) CreateRegistryRepository() (repository.RegistryRepository, error) {
if f.mode == ModeMock {
return mock.NewRegistryRepositoryMock(f.encryptor), nil
}
// 默认真实实现PostgreSQL
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewRegistryRepository(f.db, f.encryptor), nil
}
// CreateInstanceRepository 创建实例仓储
func (f *AdapterFactory) CreateInstanceRepository() (repository.InstanceRepository, error) {
if f.mode == ModeMock {
return mock.NewInstanceRepositoryMock(), nil
}
// 默认真实实现PostgreSQL
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewInstanceRepository(f.db), nil
}
func (f *AdapterFactory) CreateWorkspaceRepository() (repository.WorkspaceRepository, error) {
if f.mode == ModeMock {
return mock.NewWorkspaceRepositoryMock(), nil
}
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewWorkspaceRepository(f.db), nil
}
func (f *AdapterFactory) CreateWorkspaceClusterBindingRepository() (repository.WorkspaceClusterBindingRepository, error) {
if f.mode == ModeMock {
return mock.NewWorkspaceClusterBindingRepositoryMock(), nil
}
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewWorkspaceClusterBindingRepository(f.db), nil
}
func (f *AdapterFactory) CreateAuditLogRepository() (repository.AuditLogRepository, error) {
if f.mode == ModeMock {
return mock.NewAuditLogRepositoryMock(), nil
}
if err := f.ensureDBConnection(); err != nil {
return nil, err
}
return postgres.NewAuditLogRepository(f.db), nil
}
// CreateOCIClient 创建 OCI 客户端
func (f *AdapterFactory) CreateOCIClient() (repository.OCIClient, error) {
if f.mode == ModeMock {
return ociMock.NewOCIClientMock(), nil
}
// 默认真实实现ORAS SDK
return ociReal.NewOCIClient(), nil
}
// CreateHelmClient 创建 Helm 客户端
func (f *AdapterFactory) CreateHelmClient() (repository.HelmClient, error) {
if f.mode == ModeMock {
return helmMock.NewHelmClientMock(), nil
}
// 默认真实实现Helm SDK
return helmReal.NewHelmClient(), nil
}
// CreateMetricsClient 创建 Metrics 客户端
func (f *AdapterFactory) CreateMetricsClient(clusterRepo repository.ClusterRepository) repository.MetricsClient {
// Metrics client 总是使用真实的 Kubernetes API
return k8s.NewMetricsClient(clusterRepo)
}
// CreateEntryClient 创建实例入口查询客户端
func (f *AdapterFactory) CreateEntryClient() repository.InstanceEntryClient {
return k8s.NewEntryClient()
}
func (f *AdapterFactory) CreateDiagnosticsClient() repository.InstanceDiagnosticsClient {
if f.mode == ModeMock {
return k8s.NewMockDiagnosticsClient()
}
return k8s.NewDiagnosticsClient()
}
func (f *AdapterFactory) CreateTenantKubeClient() repository.TenantKubeClient {
if f.mode == ModeMock {
return k8s.NewMockTenantClient()
}
return k8s.NewTenantClient()
}
// CreateAllRepositories 一次性创建所有 Repositories
func (f *AdapterFactory) CreateAllRepositories() (*Repositories, error) {
userRepo, err := f.CreateUserRepository()
if err != nil {
return nil, fmt.Errorf("failed to create user repository: %w", err)
}
clusterRepo, err := f.CreateClusterRepository()
if err != nil {
return nil, fmt.Errorf("failed to create cluster repository: %w", err)
}
registryRepo, err := f.CreateRegistryRepository()
if err != nil {
return nil, fmt.Errorf("failed to create registry repository: %w", err)
}
instanceRepo, err := f.CreateInstanceRepository()
if err != nil {
return nil, fmt.Errorf("failed to create instance repository: %w", err)
}
workspaceRepo, err := f.CreateWorkspaceRepository()
if err != nil {
return nil, fmt.Errorf("failed to create workspace repository: %w", err)
}
bindingRepo, err := f.CreateWorkspaceClusterBindingRepository()
if err != nil {
return nil, fmt.Errorf("failed to create workspace cluster binding repository: %w", err)
}
auditRepo, err := f.CreateAuditLogRepository()
if err != nil {
return nil, fmt.Errorf("failed to create audit log repository: %w", err)
}
ociClient, err := f.CreateOCIClient()
if err != nil {
return nil, fmt.Errorf("failed to create OCI client: %w", err)
}
helmClient, err := f.CreateHelmClient()
if err != nil {
return nil, fmt.Errorf("failed to create Helm client: %w", err)
}
// 创建 Metrics client依赖 clusterRepo
metricsClient := f.CreateMetricsClient(clusterRepo)
entryClient := f.CreateEntryClient()
diagnosticsClient := f.CreateDiagnosticsClient()
tenantClient := f.CreateTenantKubeClient()
return &Repositories{
UserRepo: userRepo,
WorkspaceRepo: workspaceRepo,
BindingRepo: bindingRepo,
AuditRepo: auditRepo,
ClusterRepo: clusterRepo,
RegistryRepo: registryRepo,
InstanceRepo: instanceRepo,
OCIClient: ociClient,
HelmClient: helmClient,
MetricsClient: metricsClient,
EntryClient: entryClient,
DiagnosticsClient: diagnosticsClient,
TenantKubeClient: tenantClient,
}, nil
}
// Repositories 所有仓储的集合
type Repositories struct {
UserRepo repository.UserRepository
WorkspaceRepo repository.WorkspaceRepository
BindingRepo repository.WorkspaceClusterBindingRepository
AuditRepo repository.AuditLogRepository
ClusterRepo repository.ClusterRepository
RegistryRepo repository.RegistryRepository
InstanceRepo repository.InstanceRepository
OCIClient repository.OCIClient
HelmClient repository.HelmClient
MetricsClient repository.MetricsClient
EntryClient repository.InstanceEntryClient
DiagnosticsClient repository.InstanceDiagnosticsClient
TenantKubeClient repository.TenantKubeClient
}
// ensureDBConnection 确保数据库连接已建立
func (f *AdapterFactory) ensureDBConnection() error {
if f.db != nil {
return nil
}
if f.dbConnString == "" {
return fmt.Errorf("database connection string is required (set DATABASE_URL environment variable)")
}
db, err := postgres.NewDB(f.dbConnString)
if err != nil {
return fmt.Errorf("failed to connect to database: %w", err)
}
// 初始化数据库 schema
if err := db.InitSchema(); err != nil {
return fmt.Errorf("failed to initialize database schema: %w", err)
}
f.db = db
return nil
}
// Close 关闭工厂资源
func (f *AdapterFactory) Close() error {
if f.db != nil {
return f.db.Close()
}
return nil
}