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 }