This commit is contained in:
mangomqy
2025-11-13 02:54:06 +00:00
commit c5e51ed069
254 changed files with 54901 additions and 0 deletions

View File

@ -0,0 +1,171 @@
package entity
import (
"strings"
"time"
)
// ArtifactType Artifact 类型
type ArtifactType string
const (
ArtifactTypeChart ArtifactType = "chart" // Helm Chart
ArtifactTypeImage ArtifactType = "image" // Docker/OCI Image
ArtifactTypeOther ArtifactType = "other" // Other types
)
// Artifact OCI Artifact 领域实体
type Artifact struct {
RegistryID string
Repository string
Tag string
Digest string
Type ArtifactType
Size int64
MediaType string
ConfigType string // Config layer 的 mediaType (用于更准确的类型判断)
Annotations map[string]string
CreatedAt time.Time
}
// Repository 仓库信息
type Repository struct {
RegistryID string
Name string
TagCount int
}
// NewArtifact 创建新 Artifact
func NewArtifact(registryID, repository, tag, digest string) *Artifact {
return &Artifact{
RegistryID: registryID,
Repository: repository,
Tag: tag,
Digest: digest,
Annotations: make(map[string]string),
CreatedAt: time.Now(),
}
}
// SetType 设置 Artifact 类型(根据 mediaType 识别为 chart | image | other
// 已废弃:请使用 DetermineType() 方法,它提供更准确的类型判断
func (a *Artifact) SetType(mediaType string) {
lowerMediaType := strings.ToLower(strings.TrimSpace(mediaType))
containsAny := func(target string, keywords ...string) bool {
for _, keyword := range keywords {
if keyword != "" && strings.Contains(target, keyword) {
return true
}
}
return false
}
switch {
case lowerMediaType == "":
a.Type = ArtifactTypeOther
case containsAny(lowerMediaType,
"helm", "cncf.helm", "helm.chart", "helm+", "chart+json", "chart.v1", "helm-package", "helm.config",
):
a.Type = ArtifactTypeChart
case containsAny(lowerMediaType,
"docker", "vnd.docker", "docker.distribution", "docker.container.image",
"vnd.oci", "oci.image", "opencontainers", "container.image",
):
a.Type = ArtifactTypeImage
case strings.Contains(lowerMediaType, "image") || strings.Contains(lowerMediaType, "manifest") || strings.Contains(lowerMediaType, "container"):
a.Type = ArtifactTypeImage
default:
a.Type = ArtifactTypeOther
}
}
// DetermineType 智能判断 Artifact 类型(综合多种信息)
// 优先级:
// 1. ConfigType (config.mediaType) - 最准确
// 2. Annotations - 可能包含类型标注
// 3. Repository 名称 - charts/ 前缀暗示
// 4. MediaType - 兜底判断
func (a *Artifact) DetermineType() {
containsAny := func(target string, keywords ...string) bool {
for _, keyword := range keywords {
if keyword != "" && strings.Contains(target, keyword) {
return true
}
}
return false
}
// 1. 优先检查 ConfigType最准确的判断方式
if a.ConfigType != "" {
lowerConfigType := strings.ToLower(strings.TrimSpace(a.ConfigType))
// Helm Chart 的 config.mediaType
if containsAny(lowerConfigType,
"helm.config", "cncf.helm", "helm.chart", "chart.content",
) {
a.Type = ArtifactTypeChart
return
}
// Docker/OCI Image 的 config.mediaType
if containsAny(lowerConfigType,
"docker.container.image", "oci.image.config",
) {
a.Type = ArtifactTypeImage
return
}
}
// 2. 检查 Annotations
for key, value := range a.Annotations {
lowerKey := strings.ToLower(key)
lowerValue := strings.ToLower(value)
if containsAny(lowerKey, "helm", "chart") ||
containsAny(lowerValue, "helm", "chart") {
a.Type = ArtifactTypeChart
return
}
}
// 3. 检查 Repository 名称(辅助判断)
if strings.HasPrefix(strings.ToLower(a.Repository), "charts/") {
// charts/ 开头的仓库很可能是 Helm Chart
// 但需要结合 MediaType 进一步确认
lowerMediaType := strings.ToLower(strings.TrimSpace(a.MediaType))
// 如果是 OCI manifest 格式,很可能是以 OCI 格式存储的 Helm Chart
if strings.Contains(lowerMediaType, "oci.image.manifest") ||
strings.Contains(lowerMediaType, "vnd.oci") {
a.Type = ArtifactTypeChart
return
}
}
// 4. 回退到基于 MediaType 的判断(兜底逻辑)
lowerMediaType := strings.ToLower(strings.TrimSpace(a.MediaType))
switch {
case lowerMediaType == "":
a.Type = ArtifactTypeOther
case containsAny(lowerMediaType,
"helm", "cncf.helm", "helm.chart", "helm+", "chart+json", "chart.v1", "helm-package", "helm.config",
):
a.Type = ArtifactTypeChart
case containsAny(lowerMediaType,
"docker", "vnd.docker", "docker.distribution", "docker.container.image",
):
a.Type = ArtifactTypeImage
case strings.Contains(lowerMediaType, "image") || strings.Contains(lowerMediaType, "manifest"):
a.Type = ArtifactTypeImage
default:
a.Type = ArtifactTypeOther
}
}
// IsChart 判断是否为 Helm Chart
func (a *Artifact) IsChart() bool {
return a.Type == ArtifactTypeChart
}

View File

@ -0,0 +1,103 @@
package entity
import (
"time"
)
// Cluster Kubernetes 集群领域实体
type Cluster struct {
ID string
Name string
Host string // Kubernetes API Server URL
CAData string // Base64 encoded CA certificate
CertData string // Base64 encoded client certificate
KeyData string // Base64 encoded client key
Token string // Bearer token (alternative to cert auth)
Description string
CreatedAt time.Time
UpdatedAt time.Time
}
// NewCluster 创建新集群
func NewCluster(name, host string) *Cluster {
now := time.Now()
return &Cluster{
Name: name,
Host: host,
CreatedAt: now,
UpdatedAt: now,
}
}
// Update 更新集群信息
func (c *Cluster) Update(name, host, description string) {
if name != "" {
c.Name = name
}
if host != "" {
c.Host = host
}
c.Description = description
c.UpdatedAt = time.Now()
}
// SetCertAuth 设置证书认证
func (c *Cluster) SetCertAuth(caData, certData, keyData string) {
c.CAData = caData
c.CertData = certData
c.KeyData = keyData
c.UpdatedAt = time.Now()
}
// SetTokenAuth 设置 Token 认证
func (c *Cluster) SetTokenAuth(token string) {
c.Token = token
c.UpdatedAt = time.Now()
}
// Validate 验证集群配置
func (c *Cluster) Validate() error {
if c.Name == "" {
return ErrInvalidClusterName
}
if c.Host == "" {
return ErrInvalidClusterHost
}
// 必须有认证方式:证书或 Token
if (c.CertData == "" || c.KeyData == "") && c.Token == "" {
return ErrInvalidClusterAuth
}
return nil
}
// GetKubeConfig 生成 kubeconfig 内容
func (c *Cluster) GetKubeConfig() string {
// 如果 CAData 已经包含完整的 kubeconfig直接返回
if len(c.CAData) > 100 && (c.CAData[:11] == "apiVersion:" || c.CAData[:5] == "kind:") {
return c.CAData
}
// 否则从证书数据生成 kubeconfig
kubeconfig := `apiVersion: v1
kind: Config
clusters:
- cluster:
certificate-authority-data: ` + c.CAData + `
server: ` + c.Host + `
name: ` + c.Name + `
contexts:
- context:
cluster: ` + c.Name + `
user: ` + c.Name + `
name: ` + c.Name + `
current-context: ` + c.Name + `
users:
- name: ` + c.Name + `
user:
client-certificate-data: ` + c.CertData + `
client-key-data: ` + c.KeyData + `
`
return kubeconfig
}

View File

@ -0,0 +1,40 @@
package entity
import "errors"
// 领域错误定义
var (
// User errors
ErrInvalidUsername = errors.New("invalid username")
ErrInvalidPassword = errors.New("invalid password")
ErrUserNotFound = errors.New("user not found")
ErrUserExists = errors.New("user already exists")
ErrTokenRevoked = errors.New("token has been revoked")
// Cluster errors
ErrInvalidClusterName = errors.New("invalid cluster name")
ErrInvalidClusterHost = errors.New("invalid cluster host")
ErrInvalidClusterAuth = errors.New("invalid cluster authentication config")
ErrClusterNotFound = errors.New("cluster not found")
ErrClusterExists = errors.New("cluster already exists")
// Registry errors
ErrInvalidRegistryName = errors.New("invalid registry name")
ErrInvalidRegistryURL = errors.New("invalid registry URL")
ErrRegistryNotFound = errors.New("registry not found")
ErrRegistryExists = errors.New("registry already exists")
// Instance errors
ErrInvalidClusterID = errors.New("invalid cluster ID")
ErrInvalidInstanceName = errors.New("invalid instance name")
ErrInvalidNamespace = errors.New("invalid namespace")
ErrInvalidChart = errors.New("invalid chart name")
ErrInvalidVersion = errors.New("invalid version")
ErrInstanceNotFound = errors.New("instance not found")
ErrInstanceExists = errors.New("instance already exists")
// Artifact errors
ErrArtifactNotFound = errors.New("artifact not found")
ErrRepositoryNotFound = errors.New("repository not found")
ErrValuesSchemaNotFound = errors.New("values schema not found")
)

View File

@ -0,0 +1,185 @@
package entity
import (
"time"
)
// InstanceStatus 实例状态
type InstanceStatus string
const (
StatusDeployed InstanceStatus = "deployed"
StatusUninstalled InstanceStatus = "uninstalled"
StatusSuperseded InstanceStatus = "superseded"
StatusFailed InstanceStatus = "failed"
StatusPending InstanceStatus = "pending-install"
StatusUpgrading InstanceStatus = "pending-upgrade"
StatusRollingBack InstanceStatus = "pending-rollback"
StatusTerminating InstanceStatus = "pending-delete"
StatusUnknown InstanceStatus = "unknown"
)
// InstanceOperation 实例操作类型
type InstanceOperation string
const (
OperationNone InstanceOperation = ""
OperationInstall InstanceOperation = "install"
OperationUpgrade InstanceOperation = "upgrade"
OperationRollback InstanceOperation = "rollback"
OperationDelete InstanceOperation = "delete"
OperationSync InstanceOperation = "sync"
)
// Instance Helm 应用实例领域实体
type Instance struct {
ID string
ClusterID string
Name string // Helm Release Name
Namespace string
RegistryID string
Repository string // OCI Repository (e.g., charts/app)
Chart string // Chart Name
Version string // Chart Version
Description string
Values map[string]interface{} // Helm Values (JSON)
ValuesYAML string // Helm Values (YAML format)
Status InstanceStatus
StatusReason string
LastOperation InstanceOperation
LastError string
Revision int // Helm Release Revision
CreatedAt time.Time
UpdatedAt time.Time
}
// NewInstance 创建新实例
func NewInstance(clusterID, name, namespace, registryID, repository, chart, version string) *Instance {
now := time.Now()
return &Instance{
ClusterID: clusterID,
Name: name,
Namespace: namespace,
RegistryID: registryID,
Repository: repository,
Chart: chart,
Version: version,
Status: StatusPending,
StatusReason: "Pending install",
LastOperation: OperationInstall,
Revision: 1,
CreatedAt: now,
UpdatedAt: now,
}
}
// SetValues 设置 Helm Values
func (i *Instance) SetValues(values map[string]interface{}) {
i.Values = values
i.UpdatedAt = time.Now()
}
// SetValuesYAML 设置 YAML 格式的 Values
func (i *Instance) SetValuesYAML(yaml string) {
i.ValuesYAML = yaml
i.UpdatedAt = time.Now()
}
// UpdateStatus 更新实例状态
func (i *Instance) UpdateStatus(status InstanceStatus, revision int) {
i.Status = status
i.Revision = revision
i.UpdatedAt = time.Now()
}
// BeginOperation 标记开始执行某个操作
func (i *Instance) BeginOperation(op InstanceOperation, reason string) {
i.LastOperation = op
if pendingStatus := pendingStatusForOperation(op); pendingStatus != "" {
i.Status = pendingStatus
}
if reason != "" {
i.StatusReason = reason
}
i.LastError = ""
i.UpdatedAt = time.Now()
}
// MarkSuccess 标记操作成功
func (i *Instance) MarkSuccess(status InstanceStatus, revision int, reason string) {
if status != "" {
i.Status = status
}
if revision > 0 {
i.Revision = revision
}
i.StatusReason = reason
i.LastError = ""
i.UpdatedAt = time.Now()
}
// MarkFailure 标记操作失败
func (i *Instance) MarkFailure(reason string, err error) {
i.Status = StatusFailed
if reason != "" {
i.StatusReason = reason
}
if err != nil {
i.LastError = err.Error()
}
i.UpdatedAt = time.Now()
}
func pendingStatusForOperation(op InstanceOperation) InstanceStatus {
switch op {
case OperationInstall:
return StatusPending
case OperationUpgrade:
return StatusUpgrading
case OperationRollback:
return StatusRollingBack
case OperationDelete:
return StatusTerminating
default:
return ""
}
}
// Upgrade 升级实例
func (i *Instance) Upgrade(version string, values map[string]interface{}) {
i.Version = version
if values != nil {
i.Values = values
}
i.BeginOperation(OperationUpgrade, "Pending upgrade")
}
// Validate 验证实例配置
func (i *Instance) Validate() error {
if i.ClusterID == "" {
return ErrInvalidClusterID
}
if i.Name == "" {
return ErrInvalidInstanceName
}
if i.Namespace == "" {
return ErrInvalidNamespace
}
if i.Chart == "" {
return ErrInvalidChart
}
if i.Version == "" {
return ErrInvalidVersion
}
return nil
}
// ReleaseHistory Helm Release 历史记录
type ReleaseHistory struct {
Revision int
Updated time.Time
Status InstanceStatus
Chart string
AppVersion string
Description string
}

View File

@ -0,0 +1,43 @@
package entity
// InstanceEntry 描述实例关联的访问入口Service、Ingress 等)
type InstanceEntry struct {
Kind string
Name string
Namespace string
Type string
ClusterIP string
ExternalIPs []string
LoadBalancerIngress []string
Ports []InstanceEntryPort
Hosts []InstanceEntryHost
TLS []InstanceEntryTLS
}
// InstanceEntryPort Service 端口信息
type InstanceEntryPort struct {
Name string
Protocol string
Port int32
TargetPort string
NodePort int32
}
// InstanceEntryHost Ingress Host 配置
type InstanceEntryHost struct {
Host string
Paths []InstanceEntryPath
}
// InstanceEntryPath Ingress path 详情
type InstanceEntryPath struct {
Path string
ServiceName string
ServicePort string
}
// InstanceEntryTLS Ingress TLS 配置
type InstanceEntryTLS struct {
Hosts []string
SecretName string
}

View File

@ -0,0 +1,83 @@
package entity
import "time"
// ClusterMetrics 集群监控指标
type ClusterMetrics struct {
ClusterID string `json:"cluster_id"`
ClusterName string `json:"cluster_name"`
Status string `json:"status"` // healthy, warning, error, unknown
Uptime string `json:"uptime"`
NodeCount int `json:"node_count"`
PodCount int `json:"pod_count"`
LastCheck time.Time `json:"last_check"`
// 集群级别资源汇总
TotalCPU string `json:"total_cpu"` // 如 "8 cores"
TotalMemory string `json:"total_memory"` // 如 "32 GB"
TotalGPU int `json:"total_gpu"` // GPU 总数
UsedCPU string `json:"used_cpu"` // 如 "4.5 cores"
UsedMemory string `json:"used_memory"` // 如 "16 GB"
UsedGPU int `json:"used_gpu"` // 使用的 GPU 数
CPUUsage float64 `json:"cpu_usage"` // 百分比
MemoryUsage float64 `json:"memory_usage"` // 百分比
GPUUsage float64 `json:"gpu_usage"` // 百分比
// 单机资源最大值
MaxNodeCPU string `json:"max_node_cpu"` // 单机最大CPU容量如 "8 cores"
MaxNodeMemory string `json:"max_node_memory"` // 单机最大内存容量,如 "32 GB"
MaxNodeGPU int `json:"max_node_gpu"` // 单机最大GPU数量
MaxNodeCPUUsage float64 `json:"max_node_cpu_usage"` // 单机最高CPU使用率
MaxNodeMemUsage float64 `json:"max_node_mem_usage"` // 单机最高内存使用率
MaxNodeGPUUsage float64 `json:"max_node_gpu_usage"` // 单机最高GPU使用率
// 节点列表(简化信息)
Nodes []NodeMetrics `json:"nodes,omitempty"`
}
// NodeMetrics 节点监控指标
type NodeMetrics struct {
NodeName string `json:"node_name"`
Status string `json:"status"` // Ready, NotReady
Role string `json:"role"` // control-plane, worker
Age string `json:"age"`
PodCount int `json:"pod_count"`
// CPU 资源
CPUCapacity string `json:"cpu_capacity"` // 如 "4 cores"
CPUAllocatable string `json:"cpu_allocatable"`
CPUUsage string `json:"cpu_usage"`
CPUPercent float64 `json:"cpu_percent"`
// 内存资源
MemoryCapacity string `json:"memory_capacity"` // 如 "16 GB"
MemoryAllocatable string `json:"memory_allocatable"`
MemoryUsage string `json:"memory_usage"`
MemoryPercent float64 `json:"memory_percent"`
// GPU 资源(如果有)
GPUCapacity int `json:"gpu_capacity"` // GPU 总数
GPUUsage int `json:"gpu_usage"` // 已使用的 GPU
GPUPercent float64 `json:"gpu_percent"`
GPUType string `json:"gpu_type,omitempty"` // GPU 型号,如 "NVIDIA-Tesla-T4"
// 其他信息
OSImage string `json:"os_image,omitempty"`
KernelVersion string `json:"kernel_version,omitempty"`
ContainerRuntime string `json:"container_runtime,omitempty"`
KubeletVersion string `json:"kubelet_version,omitempty"`
}
// MonitoringSummary 监控汇总
type MonitoringSummary struct {
TotalClusters int `json:"total_clusters"`
HealthyClusters int `json:"healthy_clusters"`
WarningClusters int `json:"warning_clusters"`
ErrorClusters int `json:"error_clusters"`
TotalNodes int `json:"total_nodes"`
TotalPods int `json:"total_pods"`
LastUpdate time.Time `json:"last_update"`
}

View File

@ -0,0 +1,60 @@
package entity
import (
"time"
)
// Registry OCI Registry 领域实体
type Registry struct {
ID string
Name string
URL string
Description string
Username string
Password string
Insecure bool // 是否跳过 TLS 验证
CreatedAt time.Time
UpdatedAt time.Time
}
// NewRegistry 创建新 Registry
func NewRegistry(name, url string) *Registry {
now := time.Now()
return &Registry{
Name: name,
URL: url,
CreatedAt: now,
UpdatedAt: now,
}
}
// Update 更新 Registry 信息
func (r *Registry) Update(name, url, description string) {
if name != "" {
r.Name = name
}
if url != "" {
r.URL = url
}
r.Description = description
r.UpdatedAt = time.Now()
}
// SetCredentials 设置认证凭据
func (r *Registry) SetCredentials(username, password string) {
r.Username = username
r.Password = password
r.UpdatedAt = time.Now()
}
// Validate 验证 Registry 配置
func (r *Registry) Validate() error {
if r.Name == "" {
return ErrInvalidRegistryName
}
if r.URL == "" {
return ErrInvalidRegistryURL
}
return nil
}

View File

@ -0,0 +1,54 @@
package entity
import (
"time"
)
// User 用户领域实体
type User struct {
ID string
Username string
PasswordHash string
Email string
RevokedAfter time.Time // 全局 Token 撤销时间
CreatedAt time.Time
UpdatedAt time.Time
}
// NewUser 创建新用户
func NewUser(username, passwordHash, email string) *User {
now := time.Now()
return &User{
Username: username,
PasswordHash: passwordHash,
Email: email,
RevokedAfter: time.Unix(0, 0), // 初始值1970-01-01
CreatedAt: now,
UpdatedAt: now,
}
}
// UpdatePassword 更新密码(会触发全局登出)
func (u *User) UpdatePassword(newPasswordHash string) {
u.PasswordHash = newPasswordHash
u.RevokedAfter = time.Now() // 撤销所有旧 Token
u.UpdatedAt = time.Now()
}
// RevokeAllTokens 撤销所有 Token强制全局登出
func (u *User) RevokeAllTokens() {
u.RevokedAfter = time.Now()
u.UpdatedAt = time.Now()
}
// Validate 验证用户数据
func (u *User) Validate() error {
if u.Username == "" {
return ErrInvalidUsername
}
if u.PasswordHash == "" {
return ErrInvalidPassword
}
return nil
}