- Add GetMetrics method to MetricsClient interface and implement cluster metrics API - Add QuotaPrecheck service for validating resource quotas before deployment - Add auth DTO with role/permission models and auth handler tests - Add instance diagnostics: mounted NFS volumes, labels, annotations in pod diagnostics - Update workspace handler with GetWorkspace endpoint and shared-user list - Fix monitoring handler to use correct service method name - Add tail_lines fallback in instance handler for snake_case query params - Update nginx config for SSE log streaming support (no buffering) - Add comprehensive test coverage: auth_service_test, auth_handler_test, auth_dto_test, metrics_client_test, quota_precheck_test - Update error messages for quota validation and instance operations - ModifyModal: fix YAML lineWidth:0, modified keys summary, delta-only submit - InstanceCard: correctly disable scale-minus when replicas <= 0 - SidebarLayout: add hover transition for sidebar items - Update todo.md and lessons.md with latest fixes
229 lines
6.7 KiB
Go
229 lines
6.7 KiB
Go
package mock
|
||
|
||
import (
|
||
"context"
|
||
"fmt"
|
||
"time"
|
||
|
||
"github.com/ocdp/cluster-service/internal/domain/entity"
|
||
"github.com/ocdp/cluster-service/internal/domain/repository"
|
||
)
|
||
|
||
// HelmClientMock Helm 客户端 Mock 实现
|
||
type HelmClientMock struct {
|
||
// Mock 数据存储
|
||
releases map[string]map[string]*entity.Instance // clusterID -> releaseName -> instance
|
||
history map[string]map[string][]*entity.ReleaseHistory // clusterID -> releaseName -> []history
|
||
estimates map[string]map[string]*repository.ResourceEstimate // clusterID -> releaseName -> estimate
|
||
}
|
||
|
||
// NewHelmClientMock 创建 Mock 实现
|
||
func NewHelmClientMock() repository.HelmClient {
|
||
return &HelmClientMock{
|
||
releases: make(map[string]map[string]*entity.Instance),
|
||
history: make(map[string]map[string][]*entity.ReleaseHistory),
|
||
estimates: make(map[string]map[string]*repository.ResourceEstimate),
|
||
}
|
||
}
|
||
|
||
func (c *HelmClientMock) SetResourceEstimate(clusterID, namespace, releaseName string, estimate *repository.ResourceEstimate) {
|
||
if c.estimates[clusterID] == nil {
|
||
c.estimates[clusterID] = make(map[string]*repository.ResourceEstimate)
|
||
}
|
||
c.estimates[clusterID][fmt.Sprintf("%s/%s", namespace, releaseName)] = estimate
|
||
}
|
||
|
||
func (c *HelmClientMock) Install(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) error {
|
||
// 初始化集群数据
|
||
if c.releases[cluster.ID] == nil {
|
||
c.releases[cluster.ID] = make(map[string]*entity.Instance)
|
||
c.history[cluster.ID] = make(map[string][]*entity.ReleaseHistory)
|
||
}
|
||
|
||
// 检查是否已存在
|
||
key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name)
|
||
if _, exists := c.releases[cluster.ID][key]; exists {
|
||
return entity.ErrInstanceExists
|
||
}
|
||
|
||
// Mock 安装
|
||
instance.Status = entity.StatusDeployed
|
||
instance.Revision = 1
|
||
instance.UpdatedAt = time.Now()
|
||
|
||
c.releases[cluster.ID][key] = instance
|
||
|
||
// 添加历史记录
|
||
c.history[cluster.ID][key] = []*entity.ReleaseHistory{
|
||
{
|
||
Revision: 1,
|
||
Updated: time.Now(),
|
||
Status: entity.StatusDeployed,
|
||
Chart: fmt.Sprintf("%s-%s", instance.Chart, instance.Version),
|
||
AppVersion: instance.Version,
|
||
Description: "Install complete",
|
||
},
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
func (c *HelmClientMock) Upgrade(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) error {
|
||
key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name)
|
||
|
||
existing, exists := c.releases[cluster.ID][key]
|
||
if !exists {
|
||
return entity.ErrInstanceNotFound
|
||
}
|
||
|
||
// Mock 升级
|
||
instance.Revision = existing.Revision + 1
|
||
instance.Status = entity.StatusDeployed
|
||
instance.UpdatedAt = time.Now()
|
||
|
||
c.releases[cluster.ID][key] = instance
|
||
|
||
// 添加历史记录
|
||
history := &entity.ReleaseHistory{
|
||
Revision: instance.Revision,
|
||
Updated: time.Now(),
|
||
Status: entity.StatusDeployed,
|
||
Chart: fmt.Sprintf("%s-%s", instance.Chart, instance.Version),
|
||
AppVersion: instance.Version,
|
||
Description: "Upgrade complete",
|
||
}
|
||
c.history[cluster.ID][key] = append(c.history[cluster.ID][key], history)
|
||
|
||
return nil
|
||
}
|
||
|
||
func (c *HelmClientMock) Uninstall(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) error {
|
||
key := fmt.Sprintf("%s/%s", namespace, releaseName)
|
||
|
||
if _, exists := c.releases[cluster.ID][key]; !exists {
|
||
return entity.ErrInstanceNotFound
|
||
}
|
||
|
||
// Mock 卸载
|
||
delete(c.releases[cluster.ID], key)
|
||
|
||
return nil
|
||
}
|
||
|
||
func (c *HelmClientMock) Rollback(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string, revision int) error {
|
||
key := fmt.Sprintf("%s/%s", namespace, releaseName)
|
||
|
||
instance, exists := c.releases[cluster.ID][key]
|
||
if !exists {
|
||
return entity.ErrInstanceNotFound
|
||
}
|
||
|
||
// 检查历史记录是否存在
|
||
histories := c.history[cluster.ID][key]
|
||
if revision > len(histories) || revision < 1 {
|
||
return fmt.Errorf("revision %d not found", revision)
|
||
}
|
||
|
||
// Mock 回滚
|
||
instance.Revision = len(histories) + 1
|
||
instance.Status = entity.StatusDeployed
|
||
instance.UpdatedAt = time.Now()
|
||
|
||
c.releases[cluster.ID][key] = instance
|
||
|
||
// 添加回滚历史记录
|
||
history := &entity.ReleaseHistory{
|
||
Revision: instance.Revision,
|
||
Updated: time.Now(),
|
||
Status: entity.StatusDeployed,
|
||
Chart: instance.Chart,
|
||
AppVersion: instance.Version,
|
||
Description: fmt.Sprintf("Rollback to revision %d", revision),
|
||
}
|
||
c.history[cluster.ID][key] = append(c.history[cluster.ID][key], history)
|
||
|
||
return nil
|
||
}
|
||
|
||
func (c *HelmClientMock) GetStatus(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) (*entity.Instance, error) {
|
||
key := fmt.Sprintf("%s/%s", namespace, releaseName)
|
||
|
||
instance, exists := c.releases[cluster.ID][key]
|
||
if !exists {
|
||
return nil, entity.ErrInstanceNotFound
|
||
}
|
||
|
||
return instance, nil
|
||
}
|
||
|
||
func (c *HelmClientMock) GetHistory(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) ([]*entity.ReleaseHistory, error) {
|
||
key := fmt.Sprintf("%s/%s", namespace, releaseName)
|
||
|
||
if _, exists := c.releases[cluster.ID][key]; !exists {
|
||
return nil, entity.ErrInstanceNotFound
|
||
}
|
||
|
||
histories := c.history[cluster.ID][key]
|
||
if histories == nil {
|
||
return []*entity.ReleaseHistory{}, nil
|
||
}
|
||
|
||
return histories, nil
|
||
}
|
||
|
||
func (c *HelmClientMock) List(ctx context.Context, cluster *entity.Cluster, namespace string) ([]*entity.Instance, error) {
|
||
clusterReleases := c.releases[cluster.ID]
|
||
if clusterReleases == nil {
|
||
return []*entity.Instance{}, nil
|
||
}
|
||
|
||
instances := make([]*entity.Instance, 0)
|
||
for key, instance := range clusterReleases {
|
||
// 如果指定了 namespace,只返回该 namespace 的
|
||
if namespace != "" && namespace != "all" {
|
||
keyNamespace := instance.Namespace
|
||
if keyNamespace != namespace {
|
||
continue
|
||
}
|
||
}
|
||
instances = append(instances, c.releases[cluster.ID][key])
|
||
}
|
||
|
||
return instances, nil
|
||
}
|
||
|
||
func (c *HelmClientMock) GetValues(ctx context.Context, cluster *entity.Cluster, releaseName, namespace string) (map[string]interface{}, error) {
|
||
key := fmt.Sprintf("%s/%s", namespace, releaseName)
|
||
|
||
instance, exists := c.releases[cluster.ID][key]
|
||
if !exists {
|
||
return nil, entity.ErrInstanceNotFound
|
||
}
|
||
|
||
return instance.Values, nil
|
||
}
|
||
|
||
func (c *HelmClientMock) GetChartDefaultValues(chartPath string) (map[string]interface{}, error) {
|
||
return map[string]interface{}{
|
||
"replicaCount": 1,
|
||
"image": map[string]interface{}{
|
||
"repository": "nginx",
|
||
"tag": "latest",
|
||
},
|
||
}, nil
|
||
}
|
||
|
||
func (c *HelmClientMock) EstimateInstanceResources(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) (*repository.ResourceEstimate, error) {
|
||
clusterID := ""
|
||
if cluster != nil {
|
||
clusterID = cluster.ID
|
||
}
|
||
key := fmt.Sprintf("%s/%s", instance.Namespace, instance.Name)
|
||
if c.estimates[clusterID] != nil {
|
||
if estimate := c.estimates[clusterID][key]; estimate != nil {
|
||
return estimate, nil
|
||
}
|
||
}
|
||
return &repository.ResourceEstimate{}, nil
|
||
}
|