-
This commit is contained in:
194
faas/internal/services/runtime_service.go
Normal file
194
faas/internal/services/runtime_service.go
Normal file
@ -0,0 +1,194 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"go.uber.org/zap"
|
||||
|
||||
"github.com/RyanCopley/skybridge/faas/internal/domain"
|
||||
"github.com/RyanCopley/skybridge/faas/internal/runtime"
|
||||
"github.com/RyanCopley/skybridge/faas/internal/runtime/docker"
|
||||
)
|
||||
|
||||
type runtimeService struct {
|
||||
backends map[string]runtime.RuntimeBackend
|
||||
mutex sync.RWMutex
|
||||
logger *zap.Logger
|
||||
config *RuntimeConfig
|
||||
}
|
||||
|
||||
type RuntimeConfig struct {
|
||||
DefaultRuntime string `json:"default_runtime"`
|
||||
Backends map[string]map[string]interface{} `json:"backends"`
|
||||
}
|
||||
|
||||
func NewRuntimeService(logger *zap.Logger, config *RuntimeConfig) RuntimeService {
|
||||
if config == nil {
|
||||
config = &RuntimeConfig{
|
||||
DefaultRuntime: "docker",
|
||||
Backends: make(map[string]map[string]interface{}),
|
||||
}
|
||||
}
|
||||
|
||||
service := &runtimeService{
|
||||
backends: make(map[string]runtime.RuntimeBackend),
|
||||
logger: logger,
|
||||
config: config,
|
||||
}
|
||||
|
||||
// Initialize default Docker backend
|
||||
if err := service.initializeDockerBackend(); err != nil {
|
||||
logger.Warn("Failed to initialize Docker backend", zap.Error(err))
|
||||
}
|
||||
|
||||
return service
|
||||
}
|
||||
|
||||
func (s *runtimeService) initializeDockerBackend() error {
|
||||
// Use simple Docker backend for now
|
||||
dockerBackend := docker.NewSimpleDockerRuntime(s.logger)
|
||||
|
||||
s.mutex.Lock()
|
||||
s.backends["docker"] = dockerBackend
|
||||
s.mutex.Unlock()
|
||||
|
||||
s.logger.Info("Simple Docker runtime backend initialized")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *runtimeService) GetBackend(ctx context.Context, runtimeType string) (runtime.RuntimeBackend, error) {
|
||||
// Map domain runtime types to backend types
|
||||
backendType := s.mapRuntimeToBackend(runtimeType)
|
||||
|
||||
s.mutex.RLock()
|
||||
backend, exists := s.backends[backendType]
|
||||
s.mutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("runtime backend '%s' not available", backendType)
|
||||
}
|
||||
|
||||
// Check backend health
|
||||
if err := backend.HealthCheck(ctx); err != nil {
|
||||
s.logger.Warn("Runtime backend health check failed",
|
||||
zap.String("backend", backendType),
|
||||
zap.Error(err))
|
||||
return nil, fmt.Errorf("runtime backend '%s' is not healthy: %w", backendType, err)
|
||||
}
|
||||
|
||||
return backend, nil
|
||||
}
|
||||
|
||||
func (s *runtimeService) ListSupportedRuntimes(ctx context.Context) ([]*domain.RuntimeInfo, error) {
|
||||
runtimes := []*domain.RuntimeInfo{
|
||||
{
|
||||
Type: domain.RuntimeNodeJS18,
|
||||
Version: "18.x",
|
||||
Available: s.isRuntimeAvailable(ctx, "nodejs18"),
|
||||
DefaultImage: "node:18-alpine",
|
||||
Description: "Node.js 18.x runtime with Alpine Linux",
|
||||
},
|
||||
{
|
||||
Type: domain.RuntimePython39,
|
||||
Version: "3.9.x",
|
||||
Available: s.isRuntimeAvailable(ctx, "python3.9"),
|
||||
DefaultImage: "python:3.9-alpine",
|
||||
Description: "Python 3.9.x runtime with Alpine Linux",
|
||||
},
|
||||
{
|
||||
Type: domain.RuntimeGo120,
|
||||
Version: "1.20.x",
|
||||
Available: s.isRuntimeAvailable(ctx, "go1.20"),
|
||||
DefaultImage: "golang:1.20-alpine",
|
||||
Description: "Go 1.20.x runtime with Alpine Linux",
|
||||
},
|
||||
{
|
||||
Type: domain.RuntimeCustom,
|
||||
Version: "custom",
|
||||
Available: s.isRuntimeAvailable(ctx, "custom"),
|
||||
DefaultImage: "alpine:latest",
|
||||
Description: "Custom runtime with user-defined image",
|
||||
},
|
||||
}
|
||||
|
||||
return runtimes, nil
|
||||
}
|
||||
|
||||
func (s *runtimeService) HealthCheck(ctx context.Context, runtimeType string) error {
|
||||
backendType := s.mapRuntimeToBackend(runtimeType)
|
||||
|
||||
s.mutex.RLock()
|
||||
backend, exists := s.backends[backendType]
|
||||
s.mutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return fmt.Errorf("runtime backend '%s' not available", backendType)
|
||||
}
|
||||
|
||||
return backend.HealthCheck(ctx)
|
||||
}
|
||||
|
||||
func (s *runtimeService) GetRuntimeInfo(ctx context.Context, runtimeType string) (*runtime.RuntimeInfo, error) {
|
||||
backendType := s.mapRuntimeToBackend(runtimeType)
|
||||
|
||||
s.mutex.RLock()
|
||||
backend, exists := s.backends[backendType]
|
||||
s.mutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("runtime backend '%s' not available", backendType)
|
||||
}
|
||||
|
||||
return backend.GetInfo(ctx)
|
||||
}
|
||||
|
||||
func (s *runtimeService) ListContainers(ctx context.Context, runtimeType string) ([]runtime.ContainerInfo, error) {
|
||||
backendType := s.mapRuntimeToBackend(runtimeType)
|
||||
|
||||
s.mutex.RLock()
|
||||
backend, exists := s.backends[backendType]
|
||||
s.mutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("runtime backend '%s' not available", backendType)
|
||||
}
|
||||
|
||||
return backend.ListContainers(ctx)
|
||||
}
|
||||
|
||||
func (s *runtimeService) mapRuntimeToBackend(runtimeType string) string {
|
||||
// For now, all runtimes use Docker backend
|
||||
// In the future, we could support different backends for different runtimes
|
||||
switch runtimeType {
|
||||
case string(domain.RuntimeNodeJS18):
|
||||
return "docker"
|
||||
case string(domain.RuntimePython39):
|
||||
return "docker"
|
||||
case string(domain.RuntimeGo120):
|
||||
return "docker"
|
||||
case string(domain.RuntimeCustom):
|
||||
return "docker"
|
||||
default:
|
||||
return s.config.DefaultRuntime
|
||||
}
|
||||
}
|
||||
|
||||
func (s *runtimeService) isRuntimeAvailable(ctx context.Context, runtimeType string) bool {
|
||||
backendType := s.mapRuntimeToBackend(runtimeType)
|
||||
|
||||
s.mutex.RLock()
|
||||
backend, exists := s.backends[backendType]
|
||||
s.mutex.RUnlock()
|
||||
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
if err := backend.HealthCheck(ctx); err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user