340 lines
11 KiB
Go
340 lines
11 KiB
Go
// Package contracts contains API contracts for service management endpoints
|
|
package contracts
|
|
|
|
import "time"
|
|
|
|
// ==============================
|
|
// Request/Response Types
|
|
// ==============================
|
|
|
|
// ServiceManifest represents basic service information
|
|
type ServiceManifest struct {
|
|
Name string `json:"name"`
|
|
Description string `json:"description"`
|
|
Namespace string `json:"namespace"`
|
|
ConfigReferences []string `json:"configReferences,omitempty"`
|
|
ServiceConfig map[string]ConfigDefinition `json:"serviceConfig,omitempty"`
|
|
}
|
|
|
|
// ConfigDefinition defines config that should be prompted during service setup
|
|
type ConfigDefinition struct {
|
|
Path string `json:"path"`
|
|
Prompt string `json:"prompt"`
|
|
Default string `json:"default"`
|
|
Type string `json:"type,omitempty"`
|
|
}
|
|
|
|
// PodStatus represents the status of a single pod
|
|
type PodStatus struct {
|
|
Name string `json:"name"` // Pod name
|
|
Status string `json:"status"` // Pod phase: Running, Pending, Failed, etc.
|
|
Ready string `json:"ready"` // Ready containers e.g. "1/1", "0/1"
|
|
Restarts int `json:"restarts"` // Container restart count
|
|
Age string `json:"age"` // Human-readable age e.g. "2h", "5m"
|
|
Node string `json:"node"` // Node name where pod is scheduled
|
|
IP string `json:"ip,omitempty"` // Pod IP if available
|
|
}
|
|
|
|
// DetailedServiceStatus provides comprehensive service status
|
|
type DetailedServiceStatus struct {
|
|
Name string `json:"name"` // Service name
|
|
Namespace string `json:"namespace"` // Kubernetes namespace
|
|
DeploymentStatus string `json:"deploymentStatus"` // "Ready", "Progressing", "Degraded", "NotFound"
|
|
Replicas ReplicaStatus `json:"replicas"` // Desired/current/ready replicas
|
|
Pods []PodStatus `json:"pods"` // Pod details
|
|
Config map[string]interface{} `json:"config,omitempty"` // Current config from config.yaml
|
|
Manifest *ServiceManifest `json:"manifest,omitempty"` // Service manifest if available
|
|
LastUpdated time.Time `json:"lastUpdated"` // Timestamp of status
|
|
}
|
|
|
|
// ReplicaStatus tracks deployment replica counts
|
|
type ReplicaStatus struct {
|
|
Desired int32 `json:"desired"` // Desired replica count
|
|
Current int32 `json:"current"` // Current replica count
|
|
Ready int32 `json:"ready"` // Ready replica count
|
|
Available int32 `json:"available"` // Available replica count
|
|
}
|
|
|
|
// ServiceLogsRequest query parameters for log retrieval
|
|
type ServiceLogsRequest struct {
|
|
Container string `json:"container,omitempty"` // Specific container name (optional)
|
|
Tail int `json:"tail,omitempty"` // Number of lines from end (default: 100)
|
|
Follow bool `json:"follow,omitempty"` // Stream logs via SSE
|
|
Previous bool `json:"previous,omitempty"` // Get previous container logs
|
|
Since string `json:"since,omitempty"` // RFC3339 or duration string e.g. "10m"
|
|
}
|
|
|
|
// ServiceLogsResponse for non-streaming log retrieval
|
|
type ServiceLogsResponse struct {
|
|
Service string `json:"service"` // Service name
|
|
Namespace string `json:"namespace"` // Kubernetes namespace
|
|
Container string `json:"container,omitempty"` // Container name if specified
|
|
Lines []string `json:"lines"` // Log lines
|
|
Truncated bool `json:"truncated"` // Whether logs were truncated
|
|
Timestamp time.Time `json:"timestamp"` // Response timestamp
|
|
}
|
|
|
|
// ServiceLogsSSEEvent for streaming logs via Server-Sent Events
|
|
type ServiceLogsSSEEvent struct {
|
|
Type string `json:"type"` // "log", "error", "end"
|
|
Line string `json:"line,omitempty"` // Log line content
|
|
Error string `json:"error,omitempty"` // Error message if type="error"
|
|
Container string `json:"container,omitempty"` // Container source
|
|
Timestamp time.Time `json:"timestamp"` // Event timestamp
|
|
}
|
|
|
|
// ServiceConfigUpdate request to update service configuration
|
|
type ServiceConfigUpdate struct {
|
|
Config map[string]interface{} `json:"config"` // Configuration updates
|
|
Redeploy bool `json:"redeploy"` // Trigger recompilation/redeployment
|
|
Fetch bool `json:"fetch"` // Fetch fresh templates before redeployment
|
|
}
|
|
|
|
// ServiceConfigResponse response after config update
|
|
type ServiceConfigResponse struct {
|
|
Service string `json:"service"` // Service name
|
|
Namespace string `json:"namespace"` // Kubernetes namespace
|
|
Config map[string]interface{} `json:"config"` // Updated configuration
|
|
Redeployed bool `json:"redeployed"` // Whether service was redeployed
|
|
Message string `json:"message"` // Success/info message
|
|
}
|
|
|
|
// ==============================
|
|
// Error Response
|
|
// ==============================
|
|
|
|
// ErrorResponse standard error format for all endpoints
|
|
type ErrorResponse struct {
|
|
Error ErrorDetail `json:"error"`
|
|
}
|
|
|
|
// ErrorDetail contains error information
|
|
type ErrorDetail struct {
|
|
Code string `json:"code"` // Machine-readable error code
|
|
Message string `json:"message"` // Human-readable error message
|
|
Details map[string]interface{} `json:"details,omitempty"` // Additional error context
|
|
}
|
|
|
|
// Standard error codes
|
|
const (
|
|
ErrCodeNotFound = "SERVICE_NOT_FOUND"
|
|
ErrCodeInstanceNotFound = "INSTANCE_NOT_FOUND"
|
|
ErrCodeInvalidRequest = "INVALID_REQUEST"
|
|
ErrCodeKubectlFailed = "KUBECTL_FAILED"
|
|
ErrCodeConfigInvalid = "CONFIG_INVALID"
|
|
ErrCodeDeploymentFailed = "DEPLOYMENT_FAILED"
|
|
ErrCodeStreamingError = "STREAMING_ERROR"
|
|
ErrCodeInternalError = "INTERNAL_ERROR"
|
|
)
|
|
|
|
// ==============================
|
|
// API Endpoint Specifications
|
|
// ==============================
|
|
|
|
/*
|
|
1. GET /api/v1/instances/{name}/services/{service}/status
|
|
|
|
Purpose: Returns comprehensive service status including pods and health
|
|
Response Codes:
|
|
- 200 OK: Service status retrieved successfully
|
|
- 404 Not Found: Instance or service not found
|
|
- 500 Internal Server Error: kubectl command failed
|
|
|
|
Example Request:
|
|
GET /api/v1/instances/production/services/nginx/status
|
|
|
|
Example Response (200 OK):
|
|
{
|
|
"name": "nginx",
|
|
"namespace": "nginx",
|
|
"deploymentStatus": "Ready",
|
|
"replicas": {
|
|
"desired": 3,
|
|
"current": 3,
|
|
"ready": 3,
|
|
"available": 3
|
|
},
|
|
"pods": [
|
|
{
|
|
"name": "nginx-7c5464c66d-abc123",
|
|
"status": "Running",
|
|
"ready": "1/1",
|
|
"restarts": 0,
|
|
"age": "2h",
|
|
"node": "worker-1",
|
|
"ip": "10.42.1.5"
|
|
}
|
|
],
|
|
"config": {
|
|
"nginx.image": "nginx:1.21",
|
|
"nginx.replicas": 3
|
|
},
|
|
"manifest": {
|
|
"name": "nginx",
|
|
"description": "NGINX web server",
|
|
"namespace": "nginx"
|
|
},
|
|
"lastUpdated": "2024-01-15T10:30:00Z"
|
|
}
|
|
|
|
Example Error Response (404):
|
|
{
|
|
"error": {
|
|
"code": "SERVICE_NOT_FOUND",
|
|
"message": "Service nginx not found in instance production",
|
|
"details": {
|
|
"instance": "production",
|
|
"service": "nginx"
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
/*
|
|
2. GET /api/v1/instances/{name}/services/{service}/logs
|
|
|
|
Purpose: Retrieve or stream service logs
|
|
Query Parameters:
|
|
- container (string): Specific container name
|
|
- tail (int): Number of lines from end (default: 100, max: 5000)
|
|
- follow (bool): Stream logs via SSE (default: false)
|
|
- previous (bool): Get previous container logs (default: false)
|
|
- since (string): RFC3339 timestamp or duration (e.g. "10m")
|
|
|
|
Response Codes:
|
|
- 200 OK: Logs retrieved successfully (or SSE stream started)
|
|
- 400 Bad Request: Invalid query parameters
|
|
- 404 Not Found: Instance, service, or container not found
|
|
- 500 Internal Server Error: kubectl command failed
|
|
|
|
Example Request (buffered):
|
|
GET /api/v1/instances/production/services/nginx/logs?tail=50
|
|
|
|
Example Response (200 OK):
|
|
{
|
|
"service": "nginx",
|
|
"namespace": "nginx",
|
|
"container": "nginx",
|
|
"lines": [
|
|
"2024/01/15 10:00:00 [notice] Configuration loaded",
|
|
"2024/01/15 10:00:01 [info] Server started on port 80"
|
|
],
|
|
"truncated": false,
|
|
"timestamp": "2024-01-15T10:30:00Z"
|
|
}
|
|
|
|
Example Request (streaming):
|
|
GET /api/v1/instances/production/services/nginx/logs?follow=true
|
|
Accept: text/event-stream
|
|
|
|
Example SSE Response:
|
|
data: {"type":"log","line":"2024/01/15 10:00:00 [notice] Configuration loaded","container":"nginx","timestamp":"2024-01-15T10:30:00Z"}
|
|
|
|
data: {"type":"log","line":"2024/01/15 10:00:01 [info] Request from 10.0.0.1","container":"nginx","timestamp":"2024-01-15T10:30:01Z"}
|
|
|
|
data: {"type":"error","error":"Container restarting","timestamp":"2024-01-15T10:30:02Z"}
|
|
|
|
data: {"type":"end","timestamp":"2024-01-15T10:30:03Z"}
|
|
*/
|
|
|
|
/*
|
|
3. PATCH /api/v1/instances/{name}/services/{service}/config
|
|
|
|
Purpose: Update service configuration in config.yaml and optionally redeploy
|
|
Request Body: ServiceConfigUpdate (JSON)
|
|
Response Codes:
|
|
- 200 OK: Configuration updated successfully
|
|
- 400 Bad Request: Invalid configuration
|
|
- 404 Not Found: Instance or service not found
|
|
- 500 Internal Server Error: Update or deployment failed
|
|
|
|
Example Request:
|
|
PATCH /api/v1/instances/production/services/nginx/config
|
|
Content-Type: application/json
|
|
|
|
{
|
|
"config": {
|
|
"nginx.image": "nginx:1.22",
|
|
"nginx.replicas": 5,
|
|
"nginx.resources.memory": "512Mi"
|
|
},
|
|
"redeploy": true
|
|
}
|
|
|
|
Example Response (200 OK):
|
|
{
|
|
"service": "nginx",
|
|
"namespace": "nginx",
|
|
"config": {
|
|
"nginx.image": "nginx:1.22",
|
|
"nginx.replicas": 5,
|
|
"nginx.resources.memory": "512Mi"
|
|
},
|
|
"redeployed": true,
|
|
"message": "Service configuration updated and redeployed successfully"
|
|
}
|
|
|
|
Example Error Response (400):
|
|
{
|
|
"error": {
|
|
"code": "CONFIG_INVALID",
|
|
"message": "Invalid configuration: nginx.replicas must be a positive integer",
|
|
"details": {
|
|
"field": "nginx.replicas",
|
|
"value": -1,
|
|
"constraint": "positive integer"
|
|
}
|
|
}
|
|
}
|
|
*/
|
|
|
|
// ==============================
|
|
// Validation Rules
|
|
// ==============================
|
|
|
|
/*
|
|
Query Parameter Validation:
|
|
|
|
ServiceLogsRequest:
|
|
- tail: Must be between 1 and 5000 (default: 100)
|
|
- since: Must be valid RFC3339 timestamp or Go duration string (e.g. "5m", "1h")
|
|
- container: Must match existing container name if specified
|
|
- follow: When true, response uses Server-Sent Events (SSE)
|
|
- previous: Cannot be combined with follow=true
|
|
|
|
ServiceConfigUpdate:
|
|
- config: Must be valid YAML-compatible structure
|
|
- config keys: Must follow service's expected configuration schema
|
|
- redeploy: When true, triggers kustomize recompilation and kubectl apply
|
|
|
|
Path Parameters:
|
|
- instance name: Must match existing instance directory
|
|
- service name: Must match installed service name
|
|
*/
|
|
|
|
// ==============================
|
|
// HTTP Status Code Summary
|
|
// ==============================
|
|
|
|
/*
|
|
200 OK:
|
|
- Service status retrieved successfully
|
|
- Logs retrieved successfully (non-streaming)
|
|
- Configuration updated successfully
|
|
|
|
400 Bad Request:
|
|
- Invalid query parameters
|
|
- Invalid configuration in request body
|
|
- Validation errors
|
|
|
|
404 Not Found:
|
|
- Instance does not exist
|
|
- Service not installed in instance
|
|
- Container name not found (for logs)
|
|
|
|
500 Internal Server Error:
|
|
- kubectl command execution failed
|
|
- File system operations failed
|
|
- Unexpected errors during processing
|
|
*/
|