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
This commit is contained in:
150
backend/internal/domain/entity/workspace.go
Normal file
150
backend/internal/domain/entity/workspace.go
Normal file
@ -0,0 +1,150 @@
|
||||
package entity
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
DefaultWorkspaceID = "00000000-0000-0000-0000-000000000010"
|
||||
DefaultWorkspaceName = "default"
|
||||
)
|
||||
|
||||
type WorkspaceStatus string
|
||||
|
||||
const (
|
||||
WorkspaceActive WorkspaceStatus = "active"
|
||||
WorkspaceSuspended WorkspaceStatus = "suspended"
|
||||
)
|
||||
|
||||
type Workspace struct {
|
||||
ID string
|
||||
Name string
|
||||
Status WorkspaceStatus
|
||||
K8sNamespace string
|
||||
K8sSAName string
|
||||
DefaultClusterID string
|
||||
QuotaCPU string
|
||||
QuotaMemory string
|
||||
QuotaGPU string
|
||||
QuotaGPUMem string
|
||||
CreatedBy string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
func NewWorkspace(name, createdBy string) *Workspace {
|
||||
now := time.Now()
|
||||
return &Workspace{
|
||||
Name: name,
|
||||
Status: WorkspaceActive,
|
||||
K8sNamespace: NamespaceForWorkspace(name),
|
||||
K8sSAName: ServiceAccountForWorkspace(name),
|
||||
CreatedBy: createdBy,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
}
|
||||
|
||||
func NamespaceForWorkspace(name string) string {
|
||||
if name == "" {
|
||||
name = DefaultWorkspaceName
|
||||
}
|
||||
return prefixedDNSLabel("ocdp-ws-", name)
|
||||
}
|
||||
|
||||
func NamespaceForUser(username string) string {
|
||||
if username == "" {
|
||||
username = "user"
|
||||
}
|
||||
return prefixedDNSLabel("ocdp-u-", username)
|
||||
}
|
||||
|
||||
func ServiceAccountForWorkspace(name string) string {
|
||||
if name == "" {
|
||||
name = DefaultWorkspaceName
|
||||
}
|
||||
return prefixedDNSLabel("ocdp-ws-", name)
|
||||
}
|
||||
|
||||
func ServiceAccountForNamespace(namespace string) string {
|
||||
if namespace == "" {
|
||||
namespace = DefaultWorkspaceName
|
||||
}
|
||||
return prefixedDNSLabel("ocdp-sa-", namespace)
|
||||
}
|
||||
|
||||
func prefixedDNSLabel(prefix, value string) string {
|
||||
label := normalizeDNSLabel(value)
|
||||
maxLabelLen := 63 - len(prefix)
|
||||
if maxLabelLen < 1 {
|
||||
maxLabelLen = 1
|
||||
}
|
||||
if len(label) > maxLabelLen {
|
||||
label = strings.Trim(label[:maxLabelLen], "-")
|
||||
}
|
||||
if label == "" {
|
||||
label = DefaultWorkspaceName
|
||||
if len(label) > maxLabelLen {
|
||||
label = label[:maxLabelLen]
|
||||
}
|
||||
}
|
||||
return prefix + label
|
||||
}
|
||||
|
||||
func normalizeDNSLabel(value string) string {
|
||||
out := make([]rune, 0, len(value))
|
||||
lastDash := false
|
||||
for _, r := range value {
|
||||
valid := (r >= 'a' && r <= 'z') || (r >= '0' && r <= '9')
|
||||
if r >= 'A' && r <= 'Z' {
|
||||
r = r + ('a' - 'A')
|
||||
valid = true
|
||||
}
|
||||
if valid {
|
||||
out = append(out, r)
|
||||
lastDash = false
|
||||
continue
|
||||
}
|
||||
if !lastDash && len(out) > 0 {
|
||||
out = append(out, '-')
|
||||
lastDash = true
|
||||
}
|
||||
}
|
||||
for len(out) > 0 && out[len(out)-1] == '-' {
|
||||
out = out[:len(out)-1]
|
||||
}
|
||||
if len(out) == 0 {
|
||||
return DefaultWorkspaceName
|
||||
}
|
||||
return string(out)
|
||||
}
|
||||
|
||||
type WorkspaceClusterBinding struct {
|
||||
ID string
|
||||
WorkspaceID string
|
||||
ClusterID string
|
||||
Namespace string
|
||||
ServiceAccount string
|
||||
QuotaCPU string
|
||||
QuotaMemory string
|
||||
QuotaGPU string
|
||||
QuotaGPUMem string
|
||||
Status string
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
type AuditLog struct {
|
||||
ID string
|
||||
WorkspaceID string
|
||||
UserID string
|
||||
Action string
|
||||
ResourceType string
|
||||
ResourceID string
|
||||
ResourceName string
|
||||
Details map[string]interface{}
|
||||
IPAddress string
|
||||
UserAgent string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
Reference in New Issue
Block a user