From f51843f634ed37d02558ba49cda7c24764f928ac Mon Sep 17 00:00:00 2001 From: Julien Dessaux Date: Tue, 26 Mar 2024 08:31:53 +0100 Subject: feat(users): implemented basic user creation promise --- pkg/gonf.go | 8 ++++ pkg/users.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++ stdlib/os/linux/useradd.go | 26 +++++++++++++ 3 files changed, 129 insertions(+) create mode 100644 pkg/users.go create mode 100644 stdlib/os/linux/useradd.go 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 +} -- cgit v1.2.3