feat: billing layer v1.3.86 — PostgreSQL statistics
- internal/billing: Store interface + pgStore (pgx/v5 pool) + NoopStore - factory.go: NewStore() from BILLING_DSN env var (NoopStore fallback) - Server.billing: injected into Config, initialized in main - handleInvokeFunction: record invocation (TriggerConsole) - invokeInternalFunction: record invocation (TriggerHTTP) - handleCreateFunction: record event_type=create - handleCloneFunction: record event_type=clone - handleDeleteFunction: record event_type=delete - table: invocations (namespace, function_name, trigger_type, duration_ms, status_code...) - BILLING_DSN added to console.yaml - pgx/v5 added to go.mod/go.sum
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
|
||||
"fission-console/internal/api"
|
||||
"fission-console/internal/auth"
|
||||
"fission-console/internal/billing"
|
||||
|
||||
"k8s.io/client-go/dynamic"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
@@ -48,6 +49,8 @@ func main() {
|
||||
Demo: &auth.DemoAuthenticator{},
|
||||
}
|
||||
|
||||
billingStore := billing.NewStore()
|
||||
|
||||
srv := api.NewServer(api.Config{
|
||||
Dyn: dyn,
|
||||
Kube: kube,
|
||||
@@ -64,6 +67,7 @@ func main() {
|
||||
LLMUrl: envDefault("FISSION_LLM_URL", "https://api.aillm.ru"),
|
||||
LLMKey: os.Getenv("FISSION_LLM_KEY"),
|
||||
// --- end ai/ask feature ---
|
||||
Billing: billingStore,
|
||||
})
|
||||
|
||||
// Запускаем фоновые горутины: reaper истёкших функций
|
||||
|
||||
@@ -55,7 +55,7 @@ spec:
|
||||
serviceAccountName: fission-console
|
||||
containers:
|
||||
- name: console
|
||||
image: naeel/fission-console:v1.3.85
|
||||
image: naeel/fission-console:v1.3.86
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- containerPort: 8090
|
||||
@@ -82,6 +82,8 @@ spec:
|
||||
key: password
|
||||
- name: FISSION_STORAGESVC_URL
|
||||
value: "http://storagesvc.fission.svc.cluster.local"
|
||||
- name: BILLING_DSN
|
||||
value: "postgres://super:BQUF5ruECa1ZFlq4wYt3gPJUEmtBMkA9QNK4MM5Sd8al4ArMDlmT16DIKHYBPyif@postgresqlk8s-master.dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5.svc.cluster.local:5432/sqsdb"
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /health
|
||||
|
||||
@@ -20,6 +20,10 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/google/gnostic-models v0.7.0 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jackc/pgpassfile v1.0.0 // indirect
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
|
||||
github.com/jackc/pgx/v5 v5.9.2 // indirect
|
||||
github.com/jackc/puddle/v2 v2.2.2 // indirect
|
||||
github.com/josharian/intern v1.0.0 // indirect
|
||||
github.com/json-iterator/go v1.1.12 // indirect
|
||||
github.com/mailru/easyjson v0.7.7 // indirect
|
||||
@@ -32,6 +36,7 @@ require (
|
||||
go.yaml.in/yaml/v2 v2.4.3 // indirect
|
||||
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||
golang.org/x/oauth2 v0.30.0 // indirect
|
||||
golang.org/x/sync v0.18.0 // indirect
|
||||
golang.org/x/sys v0.38.0 // indirect
|
||||
golang.org/x/term v0.37.0 // indirect
|
||||
golang.org/x/text v0.31.0 // indirect
|
||||
|
||||
@@ -29,6 +29,14 @@ github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgY
|
||||
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
|
||||
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
|
||||
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM=
|
||||
github.com/jackc/pgx/v5 v5.9.2 h1:3ZhOzMWnR4yJ+RW1XImIPsD1aNSz4T4fyP7zlQb56hw=
|
||||
github.com/jackc/pgx/v5 v5.9.2/go.mod h1:mal1tBGAFfLHvZzaYh77YS/eC6IX9OWbRV1QIIM0Jn4=
|
||||
github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo=
|
||||
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
|
||||
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
|
||||
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
@@ -70,6 +78,7 @@ github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpE
|
||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
|
||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||
@@ -99,6 +108,8 @@ golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKl
|
||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I=
|
||||
golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||
|
||||
@@ -19,6 +19,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fission-console/internal/billing"
|
||||
"fission-console/internal/fission"
|
||||
"fission-console/internal/runtime"
|
||||
|
||||
@@ -241,6 +242,16 @@ func (s *Server) handleCloneFunction(w http.ResponseWriter, r *http.Request, src
|
||||
return
|
||||
}
|
||||
|
||||
s.billing.RecordInvocation(billing.Invocation{
|
||||
Namespace: ns,
|
||||
FunctionName: req.NewName,
|
||||
TriggerType: billing.TriggerEvent,
|
||||
StartedAt: now,
|
||||
StatusCode: http.StatusCreated,
|
||||
RecordedBy: "console",
|
||||
EventType: "clone",
|
||||
})
|
||||
|
||||
writeAnyJSON(w, http.StatusCreated, map[string]any{
|
||||
"name": req.NewName,
|
||||
"cloned_from": srcName,
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fission-console/internal/billing"
|
||||
"fission-console/internal/fission"
|
||||
"fission-console/internal/model"
|
||||
"fission-console/internal/runtime"
|
||||
@@ -275,6 +276,16 @@ func (s *Server) handleCreateFunction(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
s.billing.RecordInvocation(billing.Invocation{
|
||||
Namespace: ns,
|
||||
FunctionName: req.Name,
|
||||
TriggerType: billing.TriggerEvent,
|
||||
StartedAt: now,
|
||||
StatusCode: http.StatusCreated,
|
||||
RecordedBy: "console",
|
||||
EventType: "create",
|
||||
})
|
||||
|
||||
writeAnyJSON(w, http.StatusCreated, map[string]any{
|
||||
"name": req.Name,
|
||||
"package": pkgName,
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fission-console/internal/billing"
|
||||
"fission-console/internal/fission"
|
||||
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
@@ -228,6 +229,16 @@ func (s *Server) handleDeleteFunction(w http.ResponseWriter, r *http.Request, na
|
||||
|
||||
// (reconciler NS удалён — за FISSION_RESOURCE_NAMESPACES теперь отвечает Layer 1 NSWatcher)
|
||||
|
||||
s.billing.RecordInvocation(billing.Invocation{
|
||||
Namespace: ns,
|
||||
FunctionName: name,
|
||||
TriggerType: billing.TriggerEvent,
|
||||
StartedAt: time.Now(),
|
||||
StatusCode: http.StatusOK,
|
||||
RecordedBy: "console",
|
||||
EventType: "delete",
|
||||
})
|
||||
|
||||
writeAnyJSON(w, http.StatusOK, map[string]any{"deleted": true, "name": name, "package": pkgName})
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"fission-console/internal/billing"
|
||||
"fission-console/internal/fission"
|
||||
|
||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||
@@ -202,9 +203,26 @@ func (s *Server) handleInvokeFunction(w http.ResponseWriter, r *http.Request, na
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
|
||||
durationMS := time.Since(start).Milliseconds()
|
||||
s.billing.RecordInvocation(billing.Invocation{
|
||||
Namespace: ns,
|
||||
FunctionName: name,
|
||||
TriggerType: billing.TriggerConsole,
|
||||
Route: invokeURL,
|
||||
HTTPMethod: invokeMethod,
|
||||
StartedAt: start,
|
||||
DurationMS: durationMS,
|
||||
StatusCode: resp.StatusCode,
|
||||
RequestBytes: int64(len(bodyBytes)),
|
||||
ResponseBytes: int64(len(respBody)),
|
||||
RecordedBy: "console",
|
||||
EventType: "invoke",
|
||||
})
|
||||
|
||||
writeAnyJSON(w, http.StatusOK, map[string]any{
|
||||
"status": resp.StatusCode,
|
||||
"latency_ms": time.Since(start).Milliseconds(),
|
||||
"latency_ms": durationMS,
|
||||
"response_raw": string(respBody),
|
||||
})
|
||||
}
|
||||
@@ -311,9 +329,26 @@ func (s *Server) invokeInternalFunction(w http.ResponseWriter, r *http.Request,
|
||||
defer resp.Body.Close()
|
||||
|
||||
respBody, _ := io.ReadAll(resp.Body)
|
||||
|
||||
durationMS := time.Since(start).Milliseconds()
|
||||
s.billing.RecordInvocation(billing.Invocation{
|
||||
Namespace: namespace,
|
||||
FunctionName: functionName,
|
||||
TriggerType: billing.TriggerHTTP,
|
||||
Route: extraPath,
|
||||
HTTPMethod: r.Method,
|
||||
StartedAt: start,
|
||||
DurationMS: durationMS,
|
||||
StatusCode: resp.StatusCode,
|
||||
RequestBytes: int64(len(bodyBytes)),
|
||||
ResponseBytes: int64(len(respBody)),
|
||||
RecordedBy: "console",
|
||||
EventType: "invoke",
|
||||
})
|
||||
|
||||
writeAnyJSON(w, http.StatusOK, map[string]any{
|
||||
"status": resp.StatusCode,
|
||||
"latency_ms": time.Since(start).Milliseconds(),
|
||||
"latency_ms": durationMS,
|
||||
"response_raw": string(respBody),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"time"
|
||||
|
||||
"fission-console/internal/auth"
|
||||
"fission-console/internal/billing"
|
||||
"fission-console/internal/cloud"
|
||||
"fission-console/internal/fission"
|
||||
"fission-console/ui"
|
||||
@@ -59,6 +60,9 @@ type Server struct {
|
||||
|
||||
// nsManager управляет жизненным циклом пользовательских namespace-ов.
|
||||
nsManager *cloud.NSManager
|
||||
|
||||
// billing — слой записи статистики вызовов. NoopStore если BILLING_DSN не задан.
|
||||
billing billing.Store
|
||||
}
|
||||
|
||||
// Config содержит все параметры для создания Server.
|
||||
@@ -76,6 +80,7 @@ type Config struct {
|
||||
Authenticator auth.Authenticator // слой аутентификации
|
||||
LLMUrl string
|
||||
LLMKey string
|
||||
Billing billing.Store // слой статистики (NoopStore если не задан)
|
||||
}
|
||||
|
||||
// NewServer создаёт и настраивает HTTP Server со всеми зависимостями.
|
||||
@@ -96,6 +101,7 @@ func NewServer(cfg Config) *Server {
|
||||
llmURL: cfg.LLMUrl,
|
||||
llmKey: cfg.LLMKey,
|
||||
nsManager: cloud.NewNSManager(cfg.Dyn),
|
||||
billing: cfg.Billing,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,42 @@
|
||||
// Package billing — слой записи статистики вызовов функций.
|
||||
//
|
||||
// Независим от типа БД: снаружи виден только интерфейс Store.
|
||||
// Если BILLING_DSN не задан — работает NoopStore (тихо, не крашит).
|
||||
package billing
|
||||
|
||||
import "time"
|
||||
|
||||
// TriggerType описывает источник вызова.
|
||||
const (
|
||||
TriggerHTTP = "http" // вызов через /fn/... снаружи
|
||||
TriggerCron = "cron" // вызов по расписанию
|
||||
TriggerConsole = "console" // вызов через кнопку «Вызов» в UI
|
||||
TriggerEvent = "event" // lifecycle: create/delete/clone/update
|
||||
)
|
||||
|
||||
// Invocation — одна запись о вызове или событии функции.
|
||||
type Invocation struct {
|
||||
Namespace string // пользовательский namespace (= пользователь)
|
||||
FunctionName string // имя функции
|
||||
TriggerType string // TriggerHTTP / TriggerCron / TriggerConsole / TriggerEvent
|
||||
Route string // HTTP маршрут (/abc123/my-func), пусто для event
|
||||
HTTPMethod string // GET/POST/... пусто для event
|
||||
StartedAt time.Time // время начала
|
||||
DurationMS int64 // длительность в миллисекундах (0 для event)
|
||||
StatusCode int // HTTP статус ответа (0 для event)
|
||||
ColdStart bool // true = первый вызов после создания/простоя
|
||||
RequestBytes int64 // размер тела запроса
|
||||
ResponseBytes int64 // размер тела ответа
|
||||
ErrorMsg string // сообщение об ошибке, пусто если успех
|
||||
RecordedBy string // "console" | "router"
|
||||
EventType string // для TriggerEvent: "create" | "delete" | "clone" | "update" | "invoke"
|
||||
}
|
||||
|
||||
// Store — интерфейс записи статистики.
|
||||
// Реализации: pgStore (PostgreSQL через pgx), NoopStore (заглушка).
|
||||
type Store interface {
|
||||
// RecordInvocation записывает одно событие асинхронно (fire-and-forget).
|
||||
RecordInvocation(inv Invocation)
|
||||
// Close освобождает ресурсы (пул соединений и т.д.).
|
||||
Close()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package billing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"os"
|
||||
)
|
||||
|
||||
// NewStore создаёт Store из переменной окружения BILLING_DSN.
|
||||
// Если DSN пустой — возвращает NoopStore (статистика отключена, сервер работает нормально).
|
||||
func NewStore() Store {
|
||||
dsn := os.Getenv("BILLING_DSN")
|
||||
if dsn == "" {
|
||||
log.Printf("billing: BILLING_DSN not set, statistics disabled")
|
||||
return NoopStore{}
|
||||
}
|
||||
store, err := NewPostgresStore(context.Background(), dsn)
|
||||
if err != nil {
|
||||
log.Printf("billing: failed to connect to PostgreSQL: %v — statistics disabled", err)
|
||||
return NoopStore{}
|
||||
}
|
||||
return store
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package billing
|
||||
|
||||
// NoopStore — заглушка Store, которая тихо игнорирует все записи.
|
||||
// Используется когда BILLING_DSN не задан.
|
||||
type NoopStore struct{}
|
||||
|
||||
func (NoopStore) RecordInvocation(_ Invocation) {}
|
||||
func (NoopStore) Close() {}
|
||||
@@ -0,0 +1,90 @@
|
||||
package billing
|
||||
|
||||
import (
|
||||
"context"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
)
|
||||
|
||||
// pgStore — реализация Store поверх PostgreSQL через pgx connection pool.
|
||||
type pgStore struct {
|
||||
pool *pgxpool.Pool
|
||||
}
|
||||
|
||||
// NewPostgresStore создаёт Store с пулом соединений к PostgreSQL.
|
||||
// dsn — строка вида postgres://user:pass@host:5432/dbname
|
||||
// При ошибке подключения — возвращает ошибку, вызывающий код решает как реагировать.
|
||||
func NewPostgresStore(ctx context.Context, dsn string) (Store, error) {
|
||||
cfg, err := pgxpool.ParseConfig(dsn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cfg.MaxConns = 4
|
||||
cfg.MinConns = 1
|
||||
cfg.MaxConnIdleTime = 5 * time.Minute
|
||||
|
||||
pool, err := pgxpool.NewWithConfig(ctx, cfg)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Проверяем живость соединения
|
||||
if err := pool.Ping(ctx); err != nil {
|
||||
pool.Close()
|
||||
return nil, err
|
||||
}
|
||||
log.Printf("billing: connected to PostgreSQL")
|
||||
return &pgStore{pool: pool}, nil
|
||||
}
|
||||
|
||||
// RecordInvocation вставляет запись асинхронно — не блокирует основной поток.
|
||||
func (s *pgStore) RecordInvocation(inv Invocation) {
|
||||
go func() {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
|
||||
_, err := s.pool.Exec(ctx, `
|
||||
INSERT INTO invocations (
|
||||
namespace, function_name, trigger_type, route, http_method,
|
||||
started_at, duration_ms, status_code, cold_start,
|
||||
request_bytes, response_bytes, error_msg, recorded_by, event_type
|
||||
) VALUES (
|
||||
$1,$2,$3,$4,$5,
|
||||
$6,$7,$8,$9,
|
||||
$10,$11,$12,$13,$14
|
||||
)`,
|
||||
inv.Namespace,
|
||||
inv.FunctionName,
|
||||
inv.TriggerType,
|
||||
inv.Route,
|
||||
inv.HTTPMethod,
|
||||
inv.StartedAt,
|
||||
inv.DurationMS,
|
||||
inv.StatusCode,
|
||||
inv.ColdStart,
|
||||
inv.RequestBytes,
|
||||
inv.ResponseBytes,
|
||||
nullIfEmpty(inv.ErrorMsg),
|
||||
inv.RecordedBy,
|
||||
nullIfEmpty(inv.EventType),
|
||||
)
|
||||
if err != nil {
|
||||
log.Printf("billing: insert invocation: %v", err)
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Close закрывает пул соединений.
|
||||
func (s *pgStore) Close() {
|
||||
s.pool.Close()
|
||||
log.Printf("billing: connection pool closed")
|
||||
}
|
||||
|
||||
// nullIfEmpty возвращает nil для пустой строки (SQL NULL вместо пустой строки).
|
||||
func nullIfEmpty(s string) interface{} {
|
||||
if s == "" {
|
||||
return nil
|
||||
}
|
||||
return s
|
||||
}
|
||||
@@ -102,7 +102,7 @@
|
||||
<div class="nubes">NUBES</div>
|
||||
<div class="product">FISSION CONSOLE</div>
|
||||
</div>
|
||||
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.85</div>
|
||||
<div style="font-size:0.65rem; color:var(--text-secondary); margin-left:10px; align-self:center; opacity:0.7;">v1.3.86</div>
|
||||
</div>
|
||||
<div class="row" style="margin:0;">
|
||||
<button class="btn ghost" onclick="reloadAll()">Refresh</button>
|
||||
@@ -542,7 +542,7 @@
|
||||
</div>
|
||||
|
||||
<div class="actions" style="justify-content:space-between; align-items:center;">
|
||||
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.85</span>
|
||||
<span style="font-size:0.75rem; color:var(--text-secondary);">v1.3.86</span>
|
||||
<button class="btn ghost" onclick="closeHelp()">Закрыть</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,4 +1,66 @@
|
||||
ntazetdinov@nubes.ru
|
||||
stxVxLvM9eqssgZ
|
||||
|
||||
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoLWFwaSIsInN1YiI6IjAxOWQ3NmM1LTQyNGMtN2MyYy04OWI3LWUzZjA5OTQ5YTk4ZiIsImV4cCI6MTc5MzA3ODQzOSwiaWF0IjoxNzc3NTI2NDM5LCJqdGkiOiI4MTU1ODNkNy0xZTRkLTRiMmMtOGM5ZS0wZDZmMGU2NmJjNTciLCJhdXRoX3RpbWUiOjAsInR5cCI6IiIsImF6cCI6IiIsInNlc3Npb25fc3RhdGUiOiIiLCJhY3IiOiIiLCJhbGxvd2VkLW9yaWdpbnMiOm51bGwsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6bnVsbH0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpudWxsfX0sInNjb3BlIjoiIiwic2lkIjoiIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiIiwiQ2xpZW50SUQiOiJXWjAxMTEyIiwiY29tcGFueV9pZCI6IjhlYzcwYWMwLTU0NmQtNDJhNy04Y2ZmLTMzOWM4ZmI1MWEyMyIsImNvbXBhbnlfbmFtZSI6ItCe0J7QniDCq9Cd0KPQkdCV0KHCuyIsImlkcF91c3JfdWlkIjoiMDE5ZDc2YzUtNDI0Yy03YzJjLTg5YjctZTNmMDk5NDlhOThmIiwibG9naW4iOiJudGF6ZXRkaW5vdkBudWJlcy5ydSIsImZpcnN0bmFtZSI6ItCd0LDQuNC70YwiLCJtaWRkbGVuYW1lIjoi0KTQsNGA0LjRgtC-0LLQuNGHIiwibGFzdG5hbWUiOiLQotCw0LfQtdGC0LTQuNC90L7QsiIsImdyb3VwcyI6bnVsbCwicHJlZmVycmVkX3VzZXJuYW1lIjoiIiwiZ2l2ZW5fbmFtZSI6IiIsImZhbWlseV9uYW1lIjoiIiwiZW1haWwiOiJudGF6ZXRkaW5vdkBudWJlcy5ydSJ9.SaZsKAha45-fvKuJkLHUe_09AFsbH5QpzBVdPnjiEDQGIhl1A3ThgnM-oEh_H6CBXXfnOs2QDczzgCD8K8_tYzZKU1Wgk5lj04YW_fbTI89kHTO5wLtrAht9tFEjzBQZ-kmnG8mUK5tgqyNEjsngdQcfqVWRvneF366TiiRXk_76poUPpXWQmqdgCCKb3wq1rRgWcKDZcUC3JvDpOaqYL40zITZlM855drlJhMut4Gkg-EEk7ZGykl6YCsTRWVjFKGQ-7C-BDU2dkmIWhxzBAkvzzM2kBwvtlczCEDiUin7bXE-F_io89oJUYDzY4yPeHzwREwxCp6x9eD1NAIKKuA
|
||||
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJhdXRoLWFwaSIsInN1YiI6IjAxOWQ3NmM1LTQyNGMtN2MyYy04OWI3LWUzZjA5OTQ5YTk4ZiIsImV4cCI6MTc5MzA3ODQzOSwiaWF0IjoxNzc3NTI2NDM5LCJqdGkiOiI4MTU1ODNkNy0xZTRkLTRiMmMtOGM5ZS0wZDZmMGU2NmJjNTciLCJhdXRoX3RpbWUiOjAsInR5cCI6IiIsImF6cCI6IiIsInNlc3Npb25fc3RhdGUiOiIiLCJhY3IiOiIiLCJhbGxvd2VkLW9yaWdpbnMiOm51bGwsInJlYWxtX2FjY2VzcyI6eyJyb2xlcyI6bnVsbH0sInJlc291cmNlX2FjY2VzcyI6eyJhY2NvdW50Ijp7InJvbGVzIjpudWxsfX0sInNjb3BlIjoiIiwic2lkIjoiIiwiZW1haWxfdmVyaWZpZWQiOmZhbHNlLCJuYW1lIjoiIiwiQ2xpZW50SUQiOiJXWjAxMTEyIiwiY29tcGFueV9pZCI6IjhlYzcwYWMwLTU0NmQtNDJhNy04Y2ZmLTMzOWM4ZmI1MWEyMyIsImNvbXBhbnlfbmFtZSI6ItCe0J7QniDCq9Cd0KPQkdCV0KHCuyIsImlkcF91c3JfdWlkIjoiMDE5ZDc2YzUtNDI0Yy03YzJjLTg5YjctZTNmMDk5NDlhOThmIiwibG9naW4iOiJudGF6ZXRkaW5vdkBudWJlcy5ydSIsImZpcnN0bmFtZSI6ItCd0LDQuNC70YwiLCJtaWRkbGVuYW1lIjoi0KTQsNGA0LjRgtC-0LLQuNGHIiwibGFzdG5hbWUiOiLQotCw0LfQtdGC0LTQuNC90L7QsiIsImdyb3VwcyI6bnVsbCwicHJlZmVycmVkX3VzZXJuYW1lIjoiIiwiZ2l2ZW5fbmFtZSI6IiIsImZhbWlseV9uYW1lIjoiIiwiZW1haWwiOiJudGF6ZXRkaW5vdkBudWJlcy5ydSJ9.SaZsKAha45-fvKuJkLHUe_09AFsbH5QpzBVdPnjiEDQGIhl1A3ThgnM-oEh_H6CBXXfnOs2QDczzgCD8K8_tYzZKU1Wgk5lj04YW_fbTI89kHTO5wLtrAht9tFEjzBQZ-kmnG8mUK5tgqyNEjsngdQcfqVWRvneF366TiiRXk_76poUPpXWQmqdgCCKb3wq1rRgWcKDZcUC3JvDpOaqYL40zITZlM855drlJhMut4Gkg-EEk7ZGykl6YCsTRWVjFKGQ-7C-BDU2dkmIWhxzBAkvzzM2kBwvtlczCEDiUin7bXE-F_io89oJUYDzY4yPeHzwREwxCp6x9eD1NAIKKuA
|
||||
|
||||
----------- token on VM --------------
|
||||
https://deck-api-test.ngcloud.ru/api/v1 - для тест стенда где постгрес, файл с токеном -
|
||||
naeel@naeel-vm:~/terra/sless$ ll test.token
|
||||
-rw-r--r-- 1 naeel naeel 998 Feb 28 07:18 test.token
|
||||
|
||||
--------------------- pg IoT-PG -----------------------
|
||||
users
|
||||
JSON объект (раскройте для просмотра)
|
||||
|
||||
password:
|
||||
BQUF5ruECa1ZFlq4wYt3gPJUEmtBMkA9QNK4MM5Sd8al4ArMDlmT16DIKHYBPyif
|
||||
|
||||
username:
|
||||
super
|
||||
|
||||
Поля состояния (сгенерированные значения)
|
||||
monitoring
|
||||
{
|
||||
"resourceMetrics": "https://grafana.ngcloud.ru/d/vzjb4zd/kubernetes-pods?orgId=954&var-namespace=dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5&var-resource_realm=iot-naeel"
|
||||
}
|
||||
|
||||
users
|
||||
{
|
||||
"super": {
|
||||
"role": "ddl_user",
|
||||
"username": "super"
|
||||
}
|
||||
}
|
||||
|
||||
backups
|
||||
{}
|
||||
|
||||
databases
|
||||
{
|
||||
"sqsdb": {
|
||||
"dbName": "sqsdb",
|
||||
"dbOwner": "super"
|
||||
}
|
||||
}
|
||||
|
||||
externalConnect
|
||||
{
|
||||
"slave": {
|
||||
"ip": "",
|
||||
"fqdn": "",
|
||||
"uuid": "",
|
||||
"isExternal": false
|
||||
},
|
||||
"master": {
|
||||
"ip": "",
|
||||
"fqdn": "",
|
||||
"uuid": "",
|
||||
"isExternal": false
|
||||
}
|
||||
}
|
||||
|
||||
internalConnect
|
||||
{
|
||||
"slave": "",
|
||||
"master": "postgresqlk8s-master.dc5db45d-f8b4-4fd0-ad33-ec4dd017f2d5.svc.cluster.local"
|
||||
}
|
||||
Reference in New Issue
Block a user