Add initial Go server skeleton with HTTP handlers, middleware, job runner, and stubs

This commit is contained in:
Dev
2025-12-13 15:18:04 +00:00
commit 61570cae23
28 changed files with 921 additions and 0 deletions

View File

@@ -0,0 +1,42 @@
package exec
import (
"bytes"
"context"
"golang.org/x/sync/errgroup"
"os/exec"
"time"
)
type RunOptions struct {
Timeout time.Duration
}
type CommandRunner interface {
Run(ctx context.Context, cmd string, args []string, opts RunOptions) (string, string, error)
}
type DefaultRunner struct{}
func (r *DefaultRunner) Run(ctx context.Context, cmd string, args []string, opts RunOptions) (string, string, error) {
var stdout, stderr bytes.Buffer
execCtx := ctx
if opts.Timeout > 0 {
var cancel context.CancelFunc
execCtx, cancel = context.WithTimeout(ctx, opts.Timeout)
defer cancel()
}
eg, cctx := errgroup.WithContext(execCtx)
eg.Go(func() error {
command := exec.CommandContext(cctx, cmd, args...)
command.Stdout = &stdout
command.Stderr = &stderr
return command.Run()
})
if err := eg.Wait(); err != nil {
return stdout.String(), stderr.String(), err
}
return stdout.String(), stderr.String(), nil
}

View File

@@ -0,0 +1,15 @@
package db
import (
"context"
"database/sql"
)
// Open returns a connected DB instance. Caller should close.
func Open(ctx context.Context, dsn string) (*sql.DB, error) {
db, err := sql.Open("sqlite", dsn)
if err != nil {
return nil, err
}
return db, nil
}

View File

@@ -0,0 +1,44 @@
package db
import (
"context"
"database/sql"
"golang.org/x/crypto/bcrypt"
"log"
)
// MigrateAndSeed performs a very small migration set and seeds an admin user
func MigrateAndSeed(ctx context.Context, db *sql.DB) error {
tx, err := db.Begin()
if err != nil {
return err
}
defer tx.Rollback()
stmts := []string{
`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, username TEXT NOT NULL UNIQUE, password_hash TEXT, role TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP);`,
`CREATE TABLE IF NOT EXISTS pools (name TEXT PRIMARY KEY, guid TEXT, health TEXT, capacity TEXT);`,
`CREATE TABLE IF NOT EXISTS jobs (id TEXT PRIMARY KEY, type TEXT, status TEXT, progress INTEGER DEFAULT 0, owner TEXT, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, updated_at DATETIME);`,
}
for _, s := range stmts {
if _, err := tx.ExecContext(ctx, s); err != nil {
return err
}
}
// Seed a default admin user if not exists
var count int
if err := tx.QueryRowContext(ctx, `SELECT COUNT(1) FROM users WHERE username = 'admin'`).Scan(&count); err != nil {
log.Printf("seed check failed: %v", err)
}
if count == 0 {
// note: simple seeded password: admin (do not use in prod)
pwHash, _ := bcrypt.GenerateFromPassword([]byte("admin"), bcrypt.DefaultCost)
if _, err := tx.ExecContext(ctx, `INSERT INTO users (id, username, password_hash, role) VALUES (?, 'admin', ?, 'admin')`, "admin", string(pwHash)); err != nil {
return err
}
}
if err := tx.Commit(); err != nil {
return err
}
return nil
}

View File

@@ -0,0 +1,18 @@
package stubs
import (
"context"
"log"
)
type ISCSIAdapter struct{}
func (i *ISCSIAdapter) CreateTarget(ctx context.Context, name string) error {
log.Printf("iscsi: CreateTarget name=%s (stub)", name)
return nil
}
func (i *ISCSIAdapter) CreateLUN(ctx context.Context, target string, backstore string, lunID int) error {
log.Printf("iscsi: CreateLUN target=%s backstore=%s lun=%d (stub)", target, backstore, lunID)
return nil
}

View File

@@ -0,0 +1,18 @@
package stubs
import (
"context"
"log"
)
type MinioAdapter struct{}
func (m *MinioAdapter) ListBuckets(ctx context.Context) ([]string, error) {
log.Println("minio: ListBuckets (stub)")
return []string{"buckets"}, nil
}
func (m *MinioAdapter) CreateBucket(ctx context.Context, name string) error {
log.Printf("minio: CreateBucket %s (stub)", name)
return nil
}

View File

@@ -0,0 +1,18 @@
package stubs
import (
"context"
"log"
)
type NFSAdapter struct{}
func (n *NFSAdapter) ListExports(ctx context.Context) ([]string, error) {
log.Println("nfs: ListExports (stub)")
return []string{"/export/data"}, nil
}
func (n *NFSAdapter) CreateExport(ctx context.Context, path string) error {
log.Printf("nfs: CreateExport path=%s (stub)", path)
return nil
}

View File

@@ -0,0 +1,18 @@
package stubs
import (
"context"
"log"
)
type SambaAdapter struct{}
func (s *SambaAdapter) ListShares(ctx context.Context) ([]string, error) {
log.Println("samba: ListShares (stub)")
return []string{"share1"}, nil
}
func (s *SambaAdapter) CreateShare(ctx context.Context, name, path string) error {
log.Printf("samba: CreateShare name=%s path=%s (stub)", name, path)
return nil
}

View File

@@ -0,0 +1,18 @@
package stubs
import (
"context"
"log"
)
type ZFSAdapter struct{}
func (z *ZFSAdapter) ListPools(ctx context.Context) ([]string, error) {
log.Printf("zfs: ListPools (stub)")
return []string{"tank"}, nil
}
func (z *ZFSAdapter) CreatePool(ctx context.Context, name string, vdevs []string) error {
log.Printf("zfs: CreatePool %s (stub) vdevs=%v", name, vdevs)
return nil
}