Files
storage-appliance/cmd/appliance/main.go

115 lines
3.4 KiB
Go

package main
import (
"context"
"database/sql"
"log"
"net/http"
"os"
"os/signal"
"syscall"
"time"
"github.com/example/storage-appliance/internal/audit"
httpin "github.com/example/storage-appliance/internal/http"
iscsiinfra "github.com/example/storage-appliance/internal/infra/iscsi"
"github.com/example/storage-appliance/internal/infra/nfs"
"github.com/example/storage-appliance/internal/infra/osexec"
"github.com/example/storage-appliance/internal/infra/samba"
"github.com/example/storage-appliance/internal/infra/sqlite/db"
"github.com/example/storage-appliance/internal/infra/zfs"
"github.com/example/storage-appliance/internal/job"
iscsiSvcPkg "github.com/example/storage-appliance/internal/service/iscsi"
"github.com/example/storage-appliance/internal/service/mock"
"github.com/example/storage-appliance/internal/service/shares"
"github.com/example/storage-appliance/internal/service/storage"
_ "github.com/glebarez/sqlite"
"github.com/go-chi/chi/v5"
"github.com/google/uuid"
)
func main() {
ctx := context.Background()
// Connect simple sqlite DB (file)
dsn := "file:appliance.db?_foreign_keys=on"
sqldb, err := sql.Open("sqlite", dsn)
if err != nil {
log.Fatalf("open db: %v", err)
}
defer sqldb.Close()
// Run migrations and seed admin
if err := db.MigrateAndSeed(ctx, sqldb); err != nil {
log.Fatalf("migrate: %v", err)
}
r := chi.NewRouter()
uuidMiddleware := func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
rid := uuid.New().String()
rw := w
r = r.WithContext(context.WithValue(r.Context(), httpin.ContextKeyRequestID, rid))
rw.Header().Set("X-Request-Id", rid)
next.ServeHTTP(rw, r)
})
}
// Attach router and app dependencies
// wire mocks for now; replace with real adapters in infra
diskSvc := &mock.MockDiskService{}
// job runner uses sqlite DB and zfs adapter
zfsAdapter := zfs.NewAdapter(osexec.Default)
jobRunner := &job.Runner{DB: sqldb}
auditLogger := audit.NewSQLAuditLogger(sqldb)
jobRunner.ZFS = zfsAdapter
jobRunner.Audit = auditLogger
// storage service wiring: use zfsAdapter and jobRunner and audit logger
storageSvc := storage.NewStorageService(zfsAdapter, jobRunner, auditLogger)
nfsAdapter := nfs.NewAdapter(osexec.Default, "")
sambaAdapter := samba.NewAdapter(osexec.Default, "")
sharesSvc := shares.NewSharesService(sqldb, nfsAdapter, sambaAdapter, auditLogger)
// iSCSI adapter and service
iscsiAdapter := iscsiinfra.NewAdapter(osexec.Default)
iscsiSvc := iscsiSvcPkg.NewISCSIService(sqldb, zfsAdapter, iscsiAdapter, auditLogger)
zfsSvc := zfsAdapter
app := &httpin.App{
DB: sqldb,
DiskSvc: diskSvc,
ZFSSvc: zfsSvc,
JobRunner: jobRunner,
HTTPClient: &http.Client{},
StorageSvc: storageSvc,
ShareSvc: sharesSvc,
ISCSISvc: iscsiSvc,
Runner: osexec.Default,
}
r.Use(uuidMiddleware)
httpin.RegisterRoutes(r, app)
srv := &http.Server{
Addr: ":8080",
Handler: r,
}
// graceful shutdown
go func() {
log.Printf("Starting server on %s", srv.Addr)
if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed {
log.Fatalf("server error: %v", err)
}
}()
stop := make(chan os.Signal, 1)
signal.Notify(stop, syscall.SIGINT, syscall.SIGTERM)
<-stop
ctxShut, cancel := context.WithTimeout(ctx, 10*time.Second)
defer cancel()
if err := srv.Shutdown(ctxShut); err != nil {
log.Fatalf("server shutdown failed: %v", err)
}
log.Println("server stopped")
}