build / build (push) Successful in 1m43s
- include SMB drop-ins from /etc/samba/smb.conf.d into the generated smb.conf - keep smbd/nfs-server running while other services (/etc/exports.d, drop-ins) share, instead of disabling them when nasmon has no shares of its own - list those shares read-only on /shares - settings: RepoISO URL; poll its /api/integration/status, dashboard card, menu link, alerts for portal down, stale worker, failed jobs, unmounted publications Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
129 lines
3.4 KiB
Go
129 lines
3.4 KiB
Go
package shares
|
|
|
|
import (
|
|
"os"
|
|
"path/filepath"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
// Other services on the host (e.g. RepoISO) publish their own shares through
|
|
// drop-in files. nasmon includes the SMB drop-ins into the smb.conf it
|
|
// generates and keeps smbd / nfs-server running while any of them define a
|
|
// share, even when nasmon itself has none.
|
|
const (
|
|
DefaultSMBIncludeDir = "/etc/samba/smb.conf.d"
|
|
DefaultExportsDir = "/etc/exports.d"
|
|
)
|
|
|
|
// ExternalShare is a share defined outside nasmon (read-only in the UI).
|
|
type ExternalShare struct {
|
|
Kind string // smb | nfs
|
|
Source string // drop-in file name without extension, e.g. "repoiso"
|
|
Name string // SMB share name (empty for NFS)
|
|
Path string
|
|
Clients string // NFS clients with options, as written in the file
|
|
}
|
|
|
|
// IncludeFiles lists the *.conf drop-ins in dir, sorted. A missing dir yields nil.
|
|
func IncludeFiles(dir string) []string {
|
|
if dir == "" {
|
|
return nil
|
|
}
|
|
m, _ := filepath.Glob(filepath.Join(dir, "*.conf"))
|
|
sort.Strings(m)
|
|
return m
|
|
}
|
|
|
|
func sourceName(file string) string {
|
|
return strings.TrimSuffix(filepath.Base(file), filepath.Ext(file))
|
|
}
|
|
|
|
// ParseSMBDropIn returns the shares ([section] other than [global], [homes],
|
|
// [printers]) defined in a Samba config fragment.
|
|
func ParseSMBDropIn(text, source string) []ExternalShare {
|
|
var out []ExternalShare
|
|
var cur *ExternalShare
|
|
for _, raw := range strings.Split(text, "\n") {
|
|
line := strings.TrimSpace(raw)
|
|
if line == "" || line[0] == '#' || line[0] == ';' {
|
|
continue
|
|
}
|
|
if strings.HasPrefix(line, "[") && strings.HasSuffix(line, "]") {
|
|
name := strings.TrimSpace(line[1 : len(line)-1])
|
|
switch strings.ToLower(name) {
|
|
case "global", "homes", "printers":
|
|
cur = nil
|
|
default:
|
|
out = append(out, ExternalShare{Kind: "smb", Source: source, Name: name})
|
|
cur = &out[len(out)-1]
|
|
}
|
|
continue
|
|
}
|
|
if cur == nil {
|
|
continue
|
|
}
|
|
if k, v, ok := strings.Cut(line, "="); ok && strings.EqualFold(strings.TrimSpace(k), "path") {
|
|
cur.Path = strings.TrimSpace(v)
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
// ParseExportsFile returns the exports in an exports(5) file.
|
|
func ParseExportsFile(text, source string) []ExternalShare {
|
|
var out []ExternalShare
|
|
for _, raw := range strings.Split(text, "\n") {
|
|
line := strings.TrimSpace(raw)
|
|
if line == "" || line[0] == '#' {
|
|
continue
|
|
}
|
|
var path, rest string
|
|
if line[0] == '"' {
|
|
if end := strings.Index(line[1:], `"`); end >= 0 {
|
|
path, rest = line[1:end+1], line[end+2:]
|
|
}
|
|
} else {
|
|
path, rest, _ = strings.Cut(line, " ")
|
|
}
|
|
if path == "" {
|
|
continue
|
|
}
|
|
out = append(out, ExternalShare{Kind: "nfs", Source: source, Path: path, Clients: strings.TrimSpace(rest)})
|
|
}
|
|
return out
|
|
}
|
|
|
|
// External reads the SMB drop-ins and the exports.d files of other services.
|
|
func (m *Manager) External() []ExternalShare {
|
|
var out []ExternalShare
|
|
for _, f := range IncludeFiles(m.IncludeDir) {
|
|
if b, err := os.ReadFile(f); err == nil {
|
|
out = append(out, ParseSMBDropIn(string(b), sourceName(f))...)
|
|
}
|
|
}
|
|
if m.ExportsDir != "" {
|
|
files, _ := filepath.Glob(filepath.Join(m.ExportsDir, "*.exports"))
|
|
sort.Strings(files)
|
|
for _, f := range files {
|
|
if filepath.Clean(f) == filepath.Clean(m.Exports) {
|
|
continue
|
|
}
|
|
if b, err := os.ReadFile(f); err == nil {
|
|
out = append(out, ParseExportsFile(string(b), sourceName(f))...)
|
|
}
|
|
}
|
|
}
|
|
return out
|
|
}
|
|
|
|
func countKind(ext []ExternalShare, kind string) int {
|
|
n := 0
|
|
for _, e := range ext {
|
|
if e.Kind == kind {
|
|
n++
|
|
}
|
|
}
|
|
return n
|
|
}
|