restructure: console→client-console, add admin-console skeleton, move docs to doc/
This commit is contained in:
@@ -0,0 +1,128 @@
|
||||
// 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
|
||||
}
|
||||
Reference in New Issue
Block a user