Adds AddIngressPath and RemoveIngressPath to the Deployer interface for managing per-component ingress rules in monorepo projects. - Implement conflict retry logic for concurrent ingress updates - Add K8s client interface for testability - Add comprehensive unit tests for ingress path operations - Add component deployment and teardown methods to ComponentService - Update service templates with OpenAPI spec improvements - Add evolving-app cookbook tree for reference - Split resources.go into resources_ingress.go for path-based routing - Split component.go into component_deploy.go for deployment helpers Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
101 lines
3.7 KiB
Go
101 lines
3.7 KiB
Go
// Package domain contains pure domain models with no external dependencies.
|
|
package domain
|
|
|
|
import "time"
|
|
|
|
// DeploySpec defines a deployment request.
|
|
type DeploySpec struct {
|
|
ProjectName string // Project identifier
|
|
ComponentPath string // Component path within monorepo (e.g., "services/auth-api"), empty for single-app projects
|
|
Image string // Container image (e.g., zot.threesix.svc:5000/myapp:latest)
|
|
Domain string // Domain for ingress (e.g., myapp.threesix.ai)
|
|
Port int // Container port to expose
|
|
Replicas int // Number of replicas
|
|
EnvVars map[string]string // Plain environment variables
|
|
Secrets map[string]string // Secret environment variables (stored in K8s Secret)
|
|
BasePath string // URL path prefix for Ingress (e.g., "/api/auth", "/"); empty defaults to "/"
|
|
}
|
|
|
|
// DeploymentName returns the K8s resource name for this deployment.
|
|
// For monorepo components, it's "{project}-{component}", for single apps it's just "{project}".
|
|
func (s DeploySpec) DeploymentName() string {
|
|
if s.ComponentPath == "" {
|
|
return s.ProjectName
|
|
}
|
|
// Extract component name from path (e.g., "services/auth-api" -> "auth-api")
|
|
parts := splitPath(s.ComponentPath)
|
|
if len(parts) > 0 {
|
|
return s.ProjectName + "-" + parts[len(parts)-1]
|
|
}
|
|
return s.ProjectName
|
|
}
|
|
|
|
// splitPath splits a path like "services/auth-api" into ["services", "auth-api"].
|
|
func splitPath(path string) []string {
|
|
var parts []string
|
|
current := ""
|
|
for _, c := range path {
|
|
if c == '/' {
|
|
if current != "" {
|
|
parts = append(parts, current)
|
|
current = ""
|
|
}
|
|
} else {
|
|
current += string(c)
|
|
}
|
|
}
|
|
if current != "" {
|
|
parts = append(parts, current)
|
|
}
|
|
return parts
|
|
}
|
|
|
|
// DeployStatus represents the current state of a deployment.
|
|
type DeployStatus struct {
|
|
ProjectName string
|
|
ComponentPath string // Component path if this is a component deployment
|
|
Image string
|
|
Replicas int
|
|
ReadyReplicas int
|
|
URL string
|
|
Status DeploymentStatus
|
|
CreatedAt time.Time
|
|
UpdatedAt time.Time
|
|
}
|
|
|
|
// ComponentDeployStatus holds deployment status for a component.
|
|
type ComponentDeployStatus struct {
|
|
ComponentPath string // e.g., "services/auth-api"
|
|
ComponentName string // e.g., "auth-api"
|
|
ComponentType string // e.g., "service", "worker", "app"
|
|
Image string // Container image
|
|
Replicas int // Desired replicas
|
|
ReadyReplicas int // Ready replicas
|
|
URL string // URL if component has ingress
|
|
Status DeploymentStatus // Current status
|
|
}
|
|
|
|
// ProjectDeployStatus holds overall deployment status for a project.
|
|
type ProjectDeployStatus struct {
|
|
ProjectName string // Project identifier
|
|
Components []ComponentDeployStatus // Status of each deployed component
|
|
OverallURL string // Primary URL (usually app or main service)
|
|
}
|
|
|
|
// DeploymentStatus represents the state of a deployment.
|
|
type DeploymentStatus string
|
|
|
|
const (
|
|
DeploymentStatusNone DeploymentStatus = "none" // No deployment exists
|
|
DeploymentStatusPending DeploymentStatus = "pending" // Deployment created, waiting for pods
|
|
DeploymentStatusRunning DeploymentStatus = "running" // All pods are ready
|
|
DeploymentStatusFailed DeploymentStatus = "failed" // Pods failed to start
|
|
DeploymentStatusUpdating DeploymentStatus = "updating" // Rolling update in progress
|
|
DeploymentStatusUnknown DeploymentStatus = "unknown" // Status could not be determined
|
|
)
|
|
|
|
// IsReady returns true if the deployment is fully available.
|
|
func (s DeploymentStatus) IsReady() bool {
|
|
return s == DeploymentStatusRunning
|
|
}
|