121 lines
3.6 KiB
Go
121 lines
3.6 KiB
Go
package api
|
|
|
|
import (
|
|
"context"
|
|
"net/http"
|
|
"os"
|
|
"strings"
|
|
"time"
|
|
|
|
"fission-console/internal/fission"
|
|
|
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
|
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
|
)
|
|
|
|
// handleNSStatus возвращает статус инициализации пользовательского namespace.
|
|
// Используется UI для отображения прогресса при первом входе нового пользователя.
|
|
//
|
|
// Три стадии:
|
|
// 1. Namespace существует и Active
|
|
// 2. Namespace добавлен в FISSION_RESOURCE_NAMESPACES executor deployment
|
|
// 3. Executor pod Running + Ready (готов принимать функции)
|
|
func (s *Server) handleNSStatus(w http.ResponseWriter, r *http.Request) {
|
|
ns := s.userNS(r)
|
|
ctx, cancel := context.WithTimeout(r.Context(), 15*time.Second)
|
|
defer cancel()
|
|
|
|
fissionNS := os.Getenv("FISSION_SYSTEM_NAMESPACE")
|
|
if fissionNS == "" {
|
|
fissionNS = "fission"
|
|
}
|
|
|
|
type stageInfo struct {
|
|
Name string `json:"name"`
|
|
Done bool `json:"done"`
|
|
}
|
|
stages := []stageInfo{
|
|
{Name: "Создание пространства имён"},
|
|
{Name: "Регистрация в Fission"},
|
|
{Name: "Прогрев окружений"},
|
|
}
|
|
|
|
// Stage 1: namespace существует и Active
|
|
nsObj, err := s.dyn.Resource(fission.NamespaceGVR).Get(ctx, ns, metav1.GetOptions{})
|
|
if err == nil {
|
|
phase, _, _ := unstructured.NestedString(nsObj.Object, "status", "phase")
|
|
stages[0].Done = phase == "Active"
|
|
}
|
|
|
|
// Stage 2: namespace в FISSION_RESOURCE_NAMESPACES executor deployment
|
|
if stages[0].Done {
|
|
execDep, err2 := s.dyn.Resource(fission.DeploymentGVR).Namespace(fissionNS).Get(ctx, "executor", metav1.GetOptions{})
|
|
if err2 == nil {
|
|
stages[1].Done = nsInFissionEnv(execDep, ns)
|
|
}
|
|
}
|
|
|
|
// Stage 3: executor pod Running + Ready
|
|
if stages[1].Done {
|
|
podGVR := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "pods"}
|
|
podList, err3 := s.dyn.Resource(podGVR).Namespace(fissionNS).List(ctx, metav1.ListOptions{
|
|
LabelSelector: "svc=executor",
|
|
})
|
|
if err3 == nil {
|
|
for _, pod := range podList.Items {
|
|
phase, _, _ := unstructured.NestedString(pod.Object, "status", "phase")
|
|
if phase != "Running" {
|
|
continue
|
|
}
|
|
conditions, _, _ := unstructured.NestedSlice(pod.Object, "status", "conditions")
|
|
for _, c := range conditions {
|
|
cond, ok := c.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if cond["type"] == "Ready" && cond["status"] == "True" {
|
|
stages[2].Done = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
ready := stages[0].Done && stages[1].Done && stages[2].Done
|
|
writeAnyJSON(w, http.StatusOK, map[string]any{
|
|
"ready": ready,
|
|
"stages": stages,
|
|
})
|
|
}
|
|
|
|
// nsInFissionEnv проверяет что namespace ns содержится в FISSION_RESOURCE_NAMESPACES
|
|
// первого контейнера данного deployment.
|
|
func nsInFissionEnv(dep *unstructured.Unstructured, ns string) bool {
|
|
containers, _, _ := unstructured.NestedSlice(dep.Object, "spec", "template", "spec", "containers")
|
|
for _, c := range containers {
|
|
cont, ok := c.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
envs, _, _ := unstructured.NestedSlice(cont, "env")
|
|
for _, e := range envs {
|
|
env, ok := e.(map[string]any)
|
|
if !ok {
|
|
continue
|
|
}
|
|
if env["name"] == "FISSION_RESOURCE_NAMESPACES" {
|
|
if v, ok := env["value"].(string); ok {
|
|
for _, p := range strings.Split(v, ",") {
|
|
if strings.TrimSpace(p) == ns {
|
|
return true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break // только первый контейнер
|
|
}
|
|
return false
|
|
}
|