summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pkg/gonf.go8
-rw-r--r--pkg/users.go95
-rw-r--r--stdlib/os/linux/useradd.go26
3 files changed, 129 insertions, 0 deletions
diff --git a/pkg/gonf.go b/pkg/gonf.go
index 88edf9c..5e02176 100644
--- a/pkg/gonf.go
+++ b/pkg/gonf.go
@@ -14,6 +14,14 @@ func EnableDebugLogs() {
func Resolve() (status Status) {
for {
+ // ----- Users -------------------------------------------------
+ status = resolveUsers()
+ switch status {
+ case BROKEN:
+ return BROKEN
+ case REPAIRED:
+ continue
+ }
// ----- Files -------------------------------------------------
status = resolveFiles()
switch status {
diff --git a/pkg/users.go b/pkg/users.go
new file mode 100644
index 0000000..ca7913b
--- /dev/null
+++ b/pkg/users.go
@@ -0,0 +1,95 @@
+package gonf
+
+import (
+ "log/slog"
+)
+
+// ----- Globals ---------------------------------------------------------------
+var users []*UserPromise
+
+// users management functions
+var user_add_function func(data UserData) (Status, error)
+
+// ----- Init ------------------------------------------------------------------
+func init() {
+ users = make([]*UserPromise, 0)
+}
+
+// ----- Public ----------------------------------------------------------------
+func SetUsersConfiguration(useradd func(data UserData) (Status, error)) {
+ user_add_function = useradd
+}
+
+func User(data UserData) *UserPromise {
+ if data.Name == "" {
+ panic("User() promise invoked without specifying a username")
+ }
+ return &UserPromise{
+ chain: nil,
+ data: data,
+ states: nil,
+ status: PROMISED,
+ }
+}
+
+type UserData struct {
+ HomeDir string
+ Name string
+ System bool
+}
+
+type UserPromise struct {
+ chain []Promise
+ data UserData
+ states []string
+ status Status
+}
+
+func (u *UserPromise) IfRepaired(p ...Promise) Promise {
+ u.chain = append(u.chain, p...)
+ return u
+}
+
+func (u *UserPromise) Promise() Promise {
+ users = append(users, u)
+ return u
+}
+
+func (u *UserPromise) Resolve() {
+ var err error
+ u.status, err = user_add_function(u.data)
+ switch u.status {
+ case BROKEN:
+ slog.Error("user", "name", u.data.Name, "status", u.status, "error", err)
+ case KEPT:
+ slog.Debug("user", "name", u.data.Name, "status", u.status)
+ case REPAIRED:
+ slog.Info("user", "name", u.data.Name, "status", u.status)
+ if u.status == REPAIRED {
+ for _, pp := range u.chain {
+ pp.Resolve()
+ }
+ }
+ }
+}
+
+func (u UserPromise) Status() Status {
+ return u.status
+}
+
+// ----- Internal --------------------------------------------------------------
+func resolveUsers() (status Status) {
+ status = KEPT
+ for _, c := range users {
+ if c.status == PROMISED {
+ c.Resolve()
+ switch c.status {
+ case BROKEN:
+ return BROKEN
+ case REPAIRED:
+ status = REPAIRED
+ }
+ }
+ }
+ return
+}
diff --git a/stdlib/os/linux/useradd.go b/stdlib/os/linux/useradd.go
new file mode 100644
index 0000000..8dfee8b
--- /dev/null
+++ b/stdlib/os/linux/useradd.go
@@ -0,0 +1,26 @@
+package linux
+
+import (
+ "git.adyxax.org/adyxax/gonf/v2/pkg"
+ "os/exec"
+)
+
+func Useradd(data gonf.UserData) (gonf.Status, error) {
+ getent := exec.Command("getent", "passwd", data.Name)
+ if err := getent.Run(); err == nil {
+ return gonf.KEPT, nil
+ }
+ args := make([]string, 0)
+ if data.HomeDir != "" {
+ args = append(args, "--home-dir="+data.HomeDir)
+ }
+ if data.System {
+ args = append(args, "--system")
+ }
+ args = append(args, data.Name)
+ cmd := exec.Command("useradd", args...)
+ if err := cmd.Run(); err != nil {
+ return gonf.BROKEN, err
+ }
+ return gonf.REPAIRED, nil
+}