fix: direct K8s scaling, replicas from K8s API, button labels, modify fetch

- Add ScaleClient using K8s API (like kubectl scale deploy --replicas=N)
  - ScaleDeployment: patch Deployment.Spec.Replicas directly
  - GetDeploymentReplicas: query actual K8s deployment replicas
  - Search by labels then fallback to deployment name match
- Wire ScaleClient to InstanceService via SetScaleClient in main.go
- ModifyModal: fetch full instance detail on open (list excludes values)
- InstanceCard: add text labels to action buttons (Entries/Diag/Modify/Delete)
  - Text visible on sm+ screens, icon-only on xs
This commit is contained in:
Ivan087
2026-05-13 14:54:24 +08:00
parent 49b92e66c3
commit 4441f58299
6 changed files with 212 additions and 51 deletions

View File

@ -17,6 +17,12 @@ import (
"k8s.io/apimachinery/pkg/api/resource"
)
// ScaleClient defines the interface for K8s-native workload scaling
type ScaleClient interface {
GetDeploymentReplicas(ctx context.Context, cluster *entity.Cluster, namespace, releaseName string) (int32, error)
ScaleDeployment(ctx context.Context, cluster *entity.Cluster, namespace, releaseName string, replicas int32) error
}
// InstanceService Helm 实例管理领域服务
type InstanceService struct {
instanceRepo repository.InstanceRepository
@ -29,6 +35,7 @@ type InstanceService struct {
diagClient repository.InstanceDiagnosticsClient
workspaceRepo repository.WorkspaceRepository
tenantClient repository.TenantKubeClient
scaleClient ScaleClient
}
// NewInstanceService 创建实例服务
@ -60,6 +67,10 @@ func (s *InstanceService) SetDiagnosticsClient(client repository.InstanceDiagnos
s.diagClient = client
}
func (s *InstanceService) SetScaleClient(client ScaleClient) {
s.scaleClient = client
}
func (s *InstanceService) SetTenantProvisioning(workspaceRepo repository.WorkspaceRepository, tenantClient repository.TenantKubeClient) {
s.workspaceRepo = workspaceRepo
s.tenantClient = tenantClient
@ -436,26 +447,44 @@ func (s *InstanceService) ScaleInstance(ctx context.Context, clusterID, instance
return nil, entity.ErrClusterNotFound
}
// Get existing Helm values and patch replicaCount
vals, err := s.helmClient.GetValues(ctx, cluster, instance.Name, instance.Namespace)
if err != nil {
return nil, fmt.Errorf("failed to get current values: %w", err)
}
if vals == nil {
vals = make(map[string]interface{})
}
vals["replicaCount"] = replicas
instance.SetValues(vals)
instance.BeginOperation(entity.OperationUpgrade, fmt.Sprintf("Scaling to %d replicas", replicas))
if err := s.instanceRepo.Update(ctx, instance); err != nil {
return nil, err
// Scale via K8s API directly (like kubectl scale deploy --replicas=N)
if s.scaleClient != nil {
if err := s.scaleClient.ScaleDeployment(ctx, cluster, instance.Namespace, instance.Name, int32(replicas)); err != nil {
return nil, fmt.Errorf("failed to scale deployment: %w", err)
}
} else {
// Fallback: Helm upgrade with replicaCount
vals, err := s.helmClient.GetValues(ctx, cluster, instance.Name, instance.Namespace)
if err != nil {
return nil, fmt.Errorf("failed to get current values: %w", err)
}
if vals == nil {
vals = make(map[string]interface{})
}
vals["replicaCount"] = replicas
instance.SetValues(vals)
instance.BeginOperation(entity.OperationUpgrade, fmt.Sprintf("Scaling to %d replicas", replicas))
if err := s.instanceRepo.Update(ctx, instance); err != nil {
return nil, err
}
go s.executeAndSyncUpgrade(context.Background(), instance.ID, cluster, nil, instance)
}
go s.executeAndSyncUpgrade(context.Background(), instance.ID, cluster, nil, instance)
return instance, nil
}
// GetRunningReplicas returns the actual K8s deployment replicas count.
func (s *InstanceService) GetRunningReplicas(ctx context.Context, cluster *entity.Cluster, instance *entity.Instance) int {
if s.scaleClient == nil {
return 0
}
r, err := s.scaleClient.GetDeploymentReplicas(ctx, cluster, instance.Namespace, instance.Name)
if err != nil {
return 0
}
return int(r)
}
// GetInstanceValuesDiff 获取实例当前 values 与 chart 默认 values 的差异
func (s *InstanceService) GetInstanceValuesDiff(ctx context.Context, clusterID, instanceID string) (*dto.InstanceValuesDiffResponse, error) {
principal, err := authz.RequirePrincipal(ctx)