Files
IoT/cmd/iot-operator/main.go
T

149 lines
4.6 KiB
Go

// ⛔⛔⛔ ЛЕГАСИ (2026-08-16) — СТАРЫЙ IoT (оператор, CRD-контроллер). В новой архитектуре не используется.
// Актуальное: HISTORY/2026-08-16-session-log.md
// Создано: 2026-04-12
// main.go — точка входа IoT managed service.
// Запускает controller-manager (IoTDevice CRD) и REST API сервер (порт 9090) в одном процессе.
// Перенесено из sless/main.go — только IoT-специфичная часть.
//
// Компоненты:
// 1. Controller-Manager (controller-runtime) — reconcile IoTDevice CRD
// 2. REST API Server (gorilla/mux) — CRUD устройств, телеметрия, MQTT auth, admin
//
// Конфигурация через env vars:
// IOT_PG_DSN — DSN для IoT Postgres (опционально)
package main
import (
"context"
"fmt"
"log/slog"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"k8s.io/apimachinery/pkg/runtime"
utilruntime "k8s.io/apimachinery/pkg/util/runtime"
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/healthz"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
iotv1alpha1 "gitea.services.ngcloud.ru/Nail/IoT/api/v1alpha1"
iotcontrollers "gitea.services.ngcloud.ru/Nail/IoT/controllers"
iotapi "gitea.services.ngcloud.ru/Nail/IoT/internal/api"
"gitea.services.ngcloud.ru/Nail/IoT/internal/api/handler"
"gitea.services.ngcloud.ru/Nail/IoT/internal/storage/iotpg"
)
var scheme = runtime.NewScheme()
func init() {
utilruntime.Must(clientgoscheme.AddToScheme(scheme))
// IoT API group iot.kube5s.ru/v1alpha1
utilruntime.Must(iotv1alpha1.AddToScheme(scheme))
}
func main() {
log := slog.New(slog.NewTextHandler(os.Stdout, &slog.HandlerOptions{Level: slog.LevelInfo}))
ctrl.SetLogger(zap.New(zap.UseDevMode(true)))
log.Info("starting IoT managed service operator")
// Controller Manager — управляет reconcile loop для IoTDevice CRD
mgr, err := ctrl.NewManager(ctrl.GetConfigOrDie(), ctrl.Options{
Scheme: scheme,
HealthProbeBindAddress: ":8081",
LeaderElection: false,
})
if err != nil {
log.Error("unable to create controller manager", "err", err)
os.Exit(1)
}
// Регистрируем IoTDevice controller
if err = (&iotcontrollers.IoTDeviceReconciler{
Client: mgr.GetClient(),
Scheme: mgr.GetScheme(),
}).SetupWithManager(mgr); err != nil {
log.Error("unable to create IoTDevice controller", "err", err)
os.Exit(1)
}
// Health/ready пробы для k8s
if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil {
log.Error("unable to set up health check", "err", err)
os.Exit(1)
}
if err := mgr.AddReadyzCheck("readyz", healthz.Ping); err != nil {
log.Error("unable to set up ready check", "err", err)
os.Exit(1)
}
// IoT Postgres — опционален (если IOT_PG_DSN не задан — телеметрия отключена)
iotPGStore, err := iotpg.NewFromEnv(log)
if err != nil {
log.Error("failed to init IoT Postgres", "err", err)
os.Exit(1)
}
if iotPGStore != nil {
defer iotPGStore.Close()
}
// REST API handler
h := &handler.Handler{
K8s: mgr.GetClient(),
Scheme: mgr.GetScheme(),
IoTPG: iotPGStore,
Log: log,
BridgeUsername: os.Getenv("MQTT_BRIDGE_USERNAME"),
BridgePassword: os.Getenv("MQTT_BRIDGE_PASSWORD"),
}
router := iotapi.NewRouter(h, log)
// HTTP API сервер на порту 9090
apiServer := &http.Server{
Addr: ":9090",
Handler: router,
ReadTimeout: 30 * time.Second,
WriteTimeout: 60 * time.Second,
}
// Запускаем API сервер в горутине
go func() {
log.Info("starting REST API server", "addr", ":9090")
if err := apiServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Error("API server failed", "err", err)
os.Exit(1)
}
}()
// Graceful shutdown
ctx, cancel := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
defer cancel()
// Запускаем controller-manager (блокирует до ctx.Done)
go func() {
log.Info("starting controller manager")
if err := mgr.Start(ctx); err != nil {
log.Error("controller manager failed", "err", err)
os.Exit(1)
}
}()
<-ctx.Done()
log.Info("shutting down IoT operator")
shutdownCtx, shutdownCancel := context.WithTimeout(context.Background(), 10*time.Second)
defer shutdownCancel()
if err := apiServer.Shutdown(shutdownCtx); err != nil {
log.Error("API server shutdown error", "err", err)
}
fmt.Println("IoT operator stopped")
}