108 lines
3.8 KiB
Go
108 lines
3.8 KiB
Go
// cmd/server/main.go — точка входа fission-console сервера.
|
|
// Отвечает только за: парсинг env vars, создание зависимостей, запуск HTTP сервера.
|
|
// Вся бизнес-логика находится в internal/api/, internal/fission/, internal/runtime/.
|
|
package main
|
|
|
|
import (
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"fission-console/internal/api"
|
|
|
|
"k8s.io/client-go/dynamic"
|
|
"k8s.io/client-go/rest"
|
|
"k8s.io/client-go/tools/clientcmd"
|
|
)
|
|
|
|
func main() {
|
|
kubeconfig := strings.TrimSpace(os.Getenv("KUBECONFIG"))
|
|
namespace := envDefault("FISSION_NAMESPACE", "default")
|
|
routerURL := strings.TrimRight(envDefault("FISSION_ROUTER_URL", "http://router.fission.svc.cluster.local"), "/")
|
|
port := envDefault("PORT", "8090")
|
|
httpTimeout := envDurationDefault("FISSION_HTTP_TIMEOUT", 30*time.Second)
|
|
invokeTimeout := envDurationDefault("FISSION_INVOKE_TIMEOUT", 20*time.Second)
|
|
|
|
// Строим kubernetes config: сначала kubeconfig файл, потом in-cluster, потом default
|
|
cfg, err := buildConfig(kubeconfig)
|
|
if err != nil {
|
|
log.Fatalf("build kube config: %v", err)
|
|
}
|
|
|
|
dyn, err := dynamic.NewForConfig(cfg)
|
|
if err != nil {
|
|
log.Fatalf("create dynamic client: %v", err)
|
|
}
|
|
|
|
srv := api.NewServer(api.Config{
|
|
Dyn: dyn,
|
|
Namespace: namespace,
|
|
RouterURL: routerURL,
|
|
HTTPTimeout: httpTimeout,
|
|
InvokeTimeout: invokeTimeout,
|
|
SATokenPath: envDefault("SA_TOKEN_PATH", "/var/run/secrets/kubernetes.io/serviceaccount/token"),
|
|
AuthUser: envDefault("FISSION_AUTH_USERNAME", ""),
|
|
AuthPass: envDefault("FISSION_AUTH_PASSWORD", ""),
|
|
TestMode: os.Getenv("FISSION_TEST_MODE") == "true",
|
|
// --- ai/ask feature ---
|
|
LLMUrl: envDefault("FISSION_LLM_URL", "https://api.aillm.ru"),
|
|
LLMKey: os.Getenv("FISSION_LLM_KEY"),
|
|
// --- end ai/ask feature ---
|
|
})
|
|
|
|
// Запускаем фоновые горутины: reaper истёкших функций + reconciler namespace-ов
|
|
nsm := srv.NSManager()
|
|
nsm.StartExpiryReaper(envDurationDefault("REAPER_INTERVAL", 5*time.Minute))
|
|
nsm.StartNSReconciler(envDurationDefault("NS_RECONCILE_INTERVAL", 2*time.Minute))
|
|
|
|
httpServer := &http.Server{
|
|
Addr: ":" + port,
|
|
Handler: srv.Handler(),
|
|
// ReadHeaderTimeout защищает от Slowloris атаки (медленная отправка заголовков)
|
|
ReadHeaderTimeout: 10 * time.Second,
|
|
}
|
|
|
|
log.Printf("fission-console listening on :%s (namespace=%s)", port, namespace)
|
|
log.Fatal(httpServer.ListenAndServe())
|
|
}
|
|
|
|
// buildConfig строит kubernetes rest.Config в порядке приоритета:
|
|
// 1. KUBECONFIG env var или флаг — для локальной разработки
|
|
// 2. In-cluster config — для запуска внутри pod
|
|
// 3. Default kubeconfig — ~/.kube/config
|
|
func buildConfig(kubeconfig string) (*rest.Config, error) {
|
|
if kubeconfig != "" {
|
|
return clientcmd.BuildConfigFromFlags("", kubeconfig)
|
|
}
|
|
cfg, err := rest.InClusterConfig()
|
|
if err == nil {
|
|
return cfg, nil
|
|
}
|
|
// Fallback: пробуем default kubeconfig (empty rules → ~/.kube/config)
|
|
loadingRules := &clientcmd.ClientConfigLoadingRules{}
|
|
clientCfg := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, &clientcmd.ConfigOverrides{})
|
|
return clientCfg.ClientConfig()
|
|
}
|
|
|
|
func envDefault(key, fallback string) string {
|
|
if v := strings.TrimSpace(os.Getenv(key)); v != "" {
|
|
return v
|
|
}
|
|
return fallback
|
|
}
|
|
|
|
func envDurationDefault(key string, fallback time.Duration) time.Duration {
|
|
raw := strings.TrimSpace(os.Getenv(key))
|
|
if raw == "" {
|
|
return fallback
|
|
}
|
|
d, err := time.ParseDuration(raw)
|
|
if err != nil || d <= 0 {
|
|
log.Printf("invalid duration for %s=%q, using default %s", key, raw, fallback)
|
|
return fallback
|
|
}
|
|
return d
|
|
}
|