Files
fission-console/client-console/internal/fission/namespace.go
T

129 lines
5.4 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// Package fission — чистый адаптер для Fission CRD API.
// Содержит только то что специфично для Fission и не зависит от облачной платформы:
// - SetupFissionNamespace: создание NS + label для Layer 1 NSWatcher + Fission ServiceAccounts + RoleBindings
// - EnsureEnvironment, CleanupEnvironmentIfUnused: управление Fission Environment CRD
// - GVR константы (client.go)
//
// Облачно-специфичные вещи (ResourceQuota, LimitRange, NetworkPolicy, NSManager) — в пакете cloud.
package fission
import (
"context"
"fmt"
"log"
"os"
"strings"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/dynamic"
)
// SetupFissionNamespace создаёт namespace с нужными метками и регистрирует в нём
// все Fission ServiceAccounts и RoleBindings. Идемпотентно.
//
// Метки на Namespace:
// - managed-by=fission-console — для фильтрации наших NS в cloud-слое
// - fission.io/managed=true — для Layer 1 NSWatcher в executor (auto-discovery)
//
// ServiceAccounts:
// - fission-fetcher, fission-builder — нужны Fission pool pods в user NS
//
// RoleBindings (cluster-admin в рамках NS):
// - Для всех Fission system SA из FISSION_SYSTEM_NAMESPACE (default: fission)
// - Почему cluster-admin, а не admin: ClusterRole "admin" не включает fission.io/* CRD-группы,
// executor получает "RBAC escalation" при создании Role. cluster-admin в RoleBinding
// (не ClusterRoleBinding) безопасен — даёт полный доступ только внутри NS.
func SetupFissionNamespace(ctx context.Context, dyn dynamic.Interface, ns string) error {
// 1. Namespace
labels := map[string]any{
"managed-by": "fission-console",
"fission.io/managed": "true", // Layer 1: executor NSWatcher auto-discovers this NS
}
if strings.HasPrefix(ns, "fission-test-") {
labels["fission-console/env"] = "test"
}
nsObj := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": "v1",
"kind": "Namespace",
"metadata": map[string]any{
"name": ns,
"labels": labels,
},
},
}
_, err := dyn.Resource(NamespaceGVR).Create(ctx, nsObj, metav1.CreateOptions{})
if err != nil && !apierrors.IsAlreadyExists(err) {
return fmt.Errorf("create namespace %s: %w", ns, err)
}
// 2. ServiceAccounts для Fission pool pods в user namespace.
// Fetcher sidecar требует fission-fetcher SA в том же NS где запускается.
saGVR := schema.GroupVersionResource{Group: "", Version: "v1", Resource: "serviceaccounts"}
for _, saName := range []string{"fission-fetcher", "fission-builder"} {
saObj := &unstructured.Unstructured{Object: map[string]any{
"apiVersion": "v1",
"kind": "ServiceAccount",
"metadata": map[string]any{"name": saName, "namespace": ns},
}}
_, saErr := dyn.Resource(saGVR).Namespace(ns).Create(ctx, saObj, metav1.CreateOptions{})
if saErr != nil && !apierrors.IsAlreadyExists(saErr) {
log.Printf("fission.SetupFissionNamespace: create SA %s/%s: %v", ns, saName, saErr)
}
}
// 3. RoleBindings для всех Fission system SA.
fissionSysNS := os.Getenv("FISSION_SYSTEM_NAMESPACE")
if fissionSysNS == "" {
fissionSysNS = "fission"
}
type rbDef struct {
name string
namespace string
binding string
}
bindings := []rbDef{
{name: "fission-executor", binding: "fission-executor-user-ns"},
{name: "fission-router", binding: "fission-router-user-ns"},
{name: "fission-buildermgr", binding: "fission-buildermgr-user-ns"},
{name: "fission-kubewatcher", binding: "fission-kubewatcher-user-ns"},
{name: "fission-timer", binding: "fission-timer-user-ns"},
{name: "fission-fetcher", binding: "fission-fetcher-system-user-ns"},
{name: "fission-builder", binding: "fission-builder-system-user-ns"},
// fetcher/builder также нужны локально (запускаются в user NS)
{name: "fission-fetcher", namespace: ns, binding: "fission-fetcher-local-user-ns"},
{name: "fission-builder", namespace: ns, binding: "fission-builder-local-user-ns"},
}
rbGVR := schema.GroupVersionResource{Group: "rbac.authorization.k8s.io", Version: "v1", Resource: "rolebindings"}
for _, rb := range bindings {
subjectNS := rb.namespace
if subjectNS == "" {
subjectNS = fissionSysNS
}
rbObj := &unstructured.Unstructured{
Object: map[string]any{
"apiVersion": "rbac.authorization.k8s.io/v1",
"kind": "RoleBinding",
"metadata": map[string]any{"name": rb.binding, "namespace": ns},
"roleRef": map[string]any{
"apiGroup": "rbac.authorization.k8s.io",
"kind": "ClusterRole",
"name": "cluster-admin",
},
"subjects": []any{map[string]any{
"kind": "ServiceAccount", "name": rb.name, "namespace": subjectNS,
}},
},
}
_, rbErr := dyn.Resource(rbGVR).Namespace(ns).Create(ctx, rbObj, metav1.CreateOptions{})
if rbErr != nil && !apierrors.IsAlreadyExists(rbErr) {
log.Printf("fission.SetupFissionNamespace: create rolebinding %s/%s@%s: %v", ns, rb.name, subjectNS, rbErr)
}
}
return nil
}