ac07499e8d
- Inject VERSION via ldflags (-X main=web.Version=) and git short SHA
- Add /api/version endpoint returning {version, commit}
- Display version in Layout sidebar footer (v0.1.6 · 8cfd405)
- Add AGENTS.md section documenting SemVer policy and bump-before-push rule
- Bump VERSION 0.1.5 -> 0.1.6 in Makefile
122 lines
3.8 KiB
Go
122 lines
3.8 KiB
Go
package main
|
|
|
|
import (
|
|
"flag"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/darroyo/nasctl/internal/db"
|
|
"github.com/darroyo/nasctl/internal/engine"
|
|
"github.com/darroyo/nasctl/internal/importer"
|
|
"github.com/darroyo/nasctl/internal/modules/nfs"
|
|
"github.com/darroyo/nasctl/internal/modules/samba"
|
|
"github.com/darroyo/nasctl/internal/modules/users"
|
|
"github.com/darroyo/nasctl/internal/web"
|
|
)
|
|
|
|
var (
|
|
version = "dev"
|
|
commit = ""
|
|
)
|
|
|
|
func main() {
|
|
addr := flag.String("addr", envOrDefault("NASCTL_ADDR", ":8080"), "HTTP listen address")
|
|
dbPath := flag.String("db", envOrDefault("NASCTL_DB", "/var/lib/nasctl/nasctl.db"), "SQLite database path")
|
|
smbConfPath := flag.String("smb-conf", envOrDefault("NASCTL_SMB_CONF", "/etc/samba/smb.conf"), "Samba config output path")
|
|
exportsPath := flag.String("exports", envOrDefault("NASCTL_EXPORTS", "/etc/exports"), "NFS exports output path")
|
|
execSystem := flag.Bool("exec-system", envOrDefault("NASCTL_EXEC_SYSTEM", "true") == "true", "Execute real system commands (reload services, useradd, etc.)")
|
|
allowedRoots := flag.String("allowed-roots", envOrDefault("NASCTL_ALLOWED_ROOTS", ""), "Comma-separated allowed root dirs for shares/exports (empty = any absolute path)")
|
|
adminUser := flag.String("admin-user", envOrDefault("NASCTL_ADMIN_USER", "admin"), "Initial admin username (only used if no admin exists)")
|
|
adminPass := flag.String("admin-pass", envOrDefault("NASCTL_ADMIN_PASSWORD", "admin"), "Initial admin password (only used if no admin exists)")
|
|
importOnBoot := flag.Bool("import-on-boot", envOrDefault("NASCTL_IMPORT_ON_BOOT", "false") == "true", "Import existing smb.conf and /etc/exports on first boot")
|
|
flag.Parse()
|
|
|
|
if err := os.MkdirAll(filepath.Dir(*dbPath), 0o755); err != nil {
|
|
log.Fatalf("create db dir: %v", err)
|
|
}
|
|
|
|
database, err := db.Open(*dbPath)
|
|
if err != nil {
|
|
log.Fatalf("open db: %v", err)
|
|
}
|
|
defer database.Close()
|
|
|
|
if err := database.Migrate(); err != nil {
|
|
log.Fatalf("migrate db: %v", err)
|
|
}
|
|
|
|
auth, err := web.NewAuthService(database)
|
|
if err != nil {
|
|
log.Fatalf("init auth: %v", err)
|
|
}
|
|
created, err := auth.EnsureAdmin(*adminUser, *adminPass)
|
|
if err != nil {
|
|
log.Fatalf("ensure admin: %v", err)
|
|
}
|
|
if created {
|
|
log.Printf("created initial admin user %q — change the password after first login", *adminUser)
|
|
}
|
|
|
|
if *importOnBoot {
|
|
result := importer.ImportOnBoot(nil, database, *smbConfPath, *exportsPath)
|
|
if result.SambaImported > 0 {
|
|
log.Printf("[importer] imported %d existing samba shares — review and apply", result.SambaImported)
|
|
}
|
|
if result.NFSImported > 0 {
|
|
log.Printf("[importer] imported %d existing nfs exports — review and apply", result.NFSImported)
|
|
}
|
|
}
|
|
|
|
sambaModule := samba.New(samba.Config{
|
|
SMBConfPath: *smbConfPath,
|
|
Reload: *execSystem,
|
|
})
|
|
nfsModule := nfs.New(nfs.Config{
|
|
ExportsPath: *exportsPath,
|
|
Reload: *execSystem,
|
|
})
|
|
usersModule := users.New(users.Config{
|
|
Execute: *execSystem,
|
|
CreateHome: true,
|
|
})
|
|
|
|
eng := engine.New(sambaModule, nfsModule, usersModule)
|
|
web.SetVersionInfo(version, commit)
|
|
srv := web.NewServer(database, eng, web.Options{
|
|
AllowedRoots: parseRoots(*allowedRoots),
|
|
Auth: auth,
|
|
SMBConfPath: *smbConfPath,
|
|
ExportsPath: *exportsPath,
|
|
})
|
|
|
|
log.Printf("nasctl %s (commit %s) listening on %s (db=%s exec-system=%v)", version, commit, *addr, *dbPath, *execSystem)
|
|
if err := http.ListenAndServe(*addr, srv.Handler()); err != nil {
|
|
log.Fatalf("server error: %v", err)
|
|
}
|
|
}
|
|
|
|
func parseRoots(raw string) []string {
|
|
if strings.TrimSpace(raw) == "" {
|
|
return nil
|
|
}
|
|
parts := strings.Split(raw, ",")
|
|
roots := make([]string, 0, len(parts))
|
|
for _, p := range parts {
|
|
p = strings.TrimSpace(p)
|
|
if p != "" {
|
|
roots = append(roots, p)
|
|
}
|
|
}
|
|
return roots
|
|
}
|
|
|
|
func envOrDefault(key, fallback string) string {
|
|
if value := os.Getenv(key); value != "" {
|
|
return value
|
|
}
|
|
return fallback
|
|
}
|