diff options
-rw-r--r-- | pkg/gonf.go | 8 | ||||
-rw-r--r-- | pkg/users.go | 95 | ||||
-rw-r--r-- | stdlib/os/linux/useradd.go | 26 |
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 +} |