Add new frontend pages for the multi-tenant OCDP platform: - Charts page (/charts): Browse Harbor OCI registries to list Helm chart repositories and versions, with deploy modal to launch charts on selected clusters - Monitoring page (/monitoring): Display cluster metrics (CPU/Memory/GPU usage) and per-node details with resource utilization bars - Chart References page (/chart-references): CRUD for chart metadata references - Values Templates page (/templates): CRUD for Helm values templates with version history and rollback support - Sidebar: Add Charts navigation, update Storage and Templates links - api.ts: Add all API client functions (clusterApi, registryApi, instanceApi, monitoringApi, storageApi, chartReferenceApi, valuesTemplateApi, workspaceApi, userApi) with full TypeScript types Note: deploy flow and values template rollback not yet end-to-end tested.
143 lines
4.5 KiB
Go
143 lines
4.5 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/ocdp/cluster-service/internal/domain/entity"
|
|
"github.com/ocdp/cluster-service/internal/domain/repository"
|
|
)
|
|
|
|
var (
|
|
ErrTemplateNotFound = errors.New("template not found")
|
|
ErrTemplateExists = errors.New("template already exists")
|
|
)
|
|
|
|
// ValuesTemplateService Values 模板领域服务
|
|
type ValuesTemplateService struct {
|
|
valuesTemplateRepo repository.ValuesTemplateRepository
|
|
chartRefRepo repository.ChartReferenceRepository
|
|
}
|
|
|
|
// NewValuesTemplateService 创建 Values 模板服务
|
|
func NewValuesTemplateService(
|
|
valuesTemplateRepo repository.ValuesTemplateRepository,
|
|
chartRefRepo repository.ChartReferenceRepository,
|
|
) *ValuesTemplateService {
|
|
return &ValuesTemplateService{
|
|
valuesTemplateRepo: valuesTemplateRepo,
|
|
chartRefRepo: chartRefRepo,
|
|
}
|
|
}
|
|
|
|
// Create 创建 Values 模板
|
|
func (s *ValuesTemplateService) Create(
|
|
ctx context.Context,
|
|
workspaceID, ownerID, chartRefID, name, description, valuesYAML string,
|
|
isDefault bool,
|
|
) (*entity.ValuesTemplate, error) {
|
|
// 检查 Chart Reference 是否存在
|
|
chartRef, err := s.chartRefRepo.GetByID(ctx, chartRefID)
|
|
if err != nil {
|
|
return nil, errors.New("chart reference not found")
|
|
}
|
|
|
|
// 检查名称是否已存在
|
|
existing, _ := s.valuesTemplateRepo.GetByName(ctx, workspaceID, chartRefID, name)
|
|
if existing != nil {
|
|
return nil, ErrTemplateExists
|
|
}
|
|
|
|
template := entity.NewValuesTemplate(workspaceID, ownerID, chartRef.ID, name, valuesYAML)
|
|
template.Description = description
|
|
template.IsDefault = isDefault
|
|
|
|
if err := s.valuesTemplateRepo.Create(ctx, template); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return template, nil
|
|
}
|
|
|
|
// GetByID 获取 Values 模板
|
|
func (s *ValuesTemplateService) GetByID(ctx context.Context, id string) (*entity.ValuesTemplate, error) {
|
|
template, err := s.valuesTemplateRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return nil, ErrTemplateNotFound
|
|
}
|
|
return template, nil
|
|
}
|
|
|
|
// GetByWorkspace 获取工作空间的所有 Values 模板
|
|
func (s *ValuesTemplateService) GetByWorkspace(ctx context.Context, workspaceID string) ([]*entity.ValuesTemplate, error) {
|
|
return s.valuesTemplateRepo.GetByWorkspace(ctx, workspaceID)
|
|
}
|
|
|
|
// GetByChartReference 获取 Chart Reference 的所有 Values 模板
|
|
func (s *ValuesTemplateService) GetByChartReference(ctx context.Context, chartRefID string) ([]*entity.ValuesTemplate, error) {
|
|
return s.valuesTemplateRepo.GetByChartReference(ctx, chartRefID)
|
|
}
|
|
|
|
// GetHistory 获取模板的版本历史
|
|
func (s *ValuesTemplateService) GetHistory(ctx context.Context, chartRefID, name string) ([]*entity.ValuesTemplate, error) {
|
|
return s.valuesTemplateRepo.GetHistory(ctx, chartRefID, name)
|
|
}
|
|
|
|
// Update 更新 Values 模板(创建新版本)
|
|
func (s *ValuesTemplateService) Update(
|
|
ctx context.Context,
|
|
id, description, valuesYAML string,
|
|
isDefault bool,
|
|
) (*entity.ValuesTemplate, error) {
|
|
template, err := s.valuesTemplateRepo.GetByID(ctx, id)
|
|
if err != nil {
|
|
return nil, ErrTemplateNotFound
|
|
}
|
|
|
|
template.Description = description
|
|
template.ValuesYAML = valuesYAML
|
|
template.IsDefault = isDefault
|
|
|
|
if err := s.valuesTemplateRepo.Update(ctx, template); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 获取最新版本
|
|
return s.valuesTemplateRepo.GetByName(ctx, template.WorkspaceID, template.ChartReferenceID, template.Name)
|
|
}
|
|
|
|
// Delete 删除 Values 模板
|
|
func (s *ValuesTemplateService) Delete(ctx context.Context, id string) error {
|
|
return s.valuesTemplateRepo.Delete(ctx, id)
|
|
}
|
|
|
|
// List 列出所有 Values 模板(管理员用)
|
|
func (s *ValuesTemplateService) List(ctx context.Context) ([]*entity.ValuesTemplate, error) {
|
|
return s.valuesTemplateRepo.List(ctx)
|
|
}
|
|
|
|
// Rollback 回滚到指定版本
|
|
func (s *ValuesTemplateService) Rollback(ctx context.Context, templateID string) (*entity.ValuesTemplate, error) {
|
|
// 获取历史版本模板
|
|
oldTemplate, err := s.valuesTemplateRepo.GetByID(ctx, templateID)
|
|
if err != nil {
|
|
return nil, ErrTemplateNotFound
|
|
}
|
|
|
|
// 重新创建该版本(创建新版本,内容与旧版本相同)
|
|
newTemplate := &entity.ValuesTemplate{
|
|
WorkspaceID: oldTemplate.WorkspaceID,
|
|
OwnerID: oldTemplate.OwnerID,
|
|
ChartReferenceID: oldTemplate.ChartReferenceID,
|
|
Name: oldTemplate.Name,
|
|
Description: oldTemplate.Description,
|
|
ValuesYAML: oldTemplate.ValuesYAML,
|
|
}
|
|
|
|
if err := s.valuesTemplateRepo.Update(ctx, newTemplate); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 获取最新版本
|
|
return s.valuesTemplateRepo.GetByName(ctx, newTemplate.WorkspaceID, newTemplate.ChartReferenceID, newTemplate.Name)
|
|
} |