Matthew Rich
e695278d0c
All checks were successful
Declarative Tests / test (push) Successful in 48s
155 lines
3.4 KiB
Go
155 lines
3.4 KiB
Go
// Copyright 2024 Matthew Rich <matthewrich.conf@gmail.com>. All rights reserved.
|
|
|
|
package resource
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"gopkg.in/yaml.v3"
|
|
"log"
|
|
"net/url"
|
|
_ "os"
|
|
"os/exec"
|
|
"os/user"
|
|
"strconv"
|
|
"strings"
|
|
)
|
|
|
|
type User struct {
|
|
loader YamlLoader
|
|
Name string `yaml:"name"`
|
|
UID int `yaml:"uid"`
|
|
Group string `yaml:"group"`
|
|
Groups []string `yaml:"groups",omitempty`
|
|
Gecos string `yaml:"gecos"`
|
|
Home string `yaml:"home"`
|
|
CreateHome bool `yaml:"createhome"omitempty`
|
|
Shell string `yaml:"shell"`
|
|
|
|
State string `yaml:"state"`
|
|
}
|
|
|
|
func NewUser() *User {
|
|
return &User{loader: YamlLoadDecl}
|
|
}
|
|
|
|
func init() {
|
|
ResourceTypes.Register("user", func(u *url.URL) Resource {
|
|
user := NewUser()
|
|
user.Name = u.Path
|
|
user.UID, _ = LookupUID(u.Path)
|
|
return user
|
|
})
|
|
}
|
|
|
|
func (u *User) URI() string {
|
|
return fmt.Sprintf("user://%s", u.Name)
|
|
}
|
|
|
|
func (u *User) ResolveId(ctx context.Context) string {
|
|
return LookupUIDString(u.Name)
|
|
}
|
|
|
|
func (u *User) Apply() error {
|
|
switch u.State {
|
|
case "present":
|
|
_, NoUserExists := LookupUID(u.Name)
|
|
if NoUserExists != nil {
|
|
var userCommandName string = "useradd"
|
|
args := make([]string, 0, 7)
|
|
if u.UID >= 0 {
|
|
args = append(args, "-u", fmt.Sprintf("%d", u.UID))
|
|
}
|
|
|
|
if _, pathErr := exec.LookPath("useradd"); pathErr != nil {
|
|
if _, addUserPathErr := exec.LookPath("adduser"); addUserPathErr == nil {
|
|
userCommandName = "adduser"
|
|
u.AddUserCommand(&args)
|
|
}
|
|
} else {
|
|
u.UserAddCommand(&args)
|
|
}
|
|
args = append(args, u.Name)
|
|
cmd := exec.Command(userCommandName, args...)
|
|
cmdOutput, cmdErr := cmd.CombinedOutput()
|
|
log.Printf("%s\n", cmdOutput)
|
|
return cmdErr
|
|
}
|
|
case "absent":
|
|
var userDelCommandName string = "userdel"
|
|
args := make([]string, 0, 7)
|
|
|
|
if _, pathErr := exec.LookPath("userdel"); pathErr != nil {
|
|
if _, delUserPathErr := exec.LookPath("deluser"); delUserPathErr == nil {
|
|
userDelCommandName = "deluser"
|
|
}
|
|
}
|
|
args = append(args, u.Name)
|
|
cmd := exec.Command(userDelCommandName, args...)
|
|
cmdOutput, cmdErr := cmd.CombinedOutput()
|
|
log.Printf("%s\n", cmdOutput)
|
|
return cmdErr
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *User) LoadDecl(yamlFileResourceDeclaration string) error {
|
|
return u.loader(yamlFileResourceDeclaration, u)
|
|
}
|
|
|
|
func (u *User) AddUserCommand(args *[]string) error {
|
|
*args = append(*args, "-D")
|
|
if u.Group != "" {
|
|
*args = append(*args, "-G", u.Group)
|
|
}
|
|
if u.Home != "" {
|
|
*args = append(*args, "-h", u.Home)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *User) UserAddCommand(args *[]string) error {
|
|
if u.Group != "" {
|
|
*args = append(*args, "-g", u.Group)
|
|
}
|
|
if len(u.Groups) > 0 {
|
|
*args = append(*args, "-G", strings.Join(u.Groups, ","))
|
|
}
|
|
if u.Home != "" {
|
|
*args = append(*args, "-d", u.Home)
|
|
}
|
|
if u.CreateHome {
|
|
*args = append(*args, "-m")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (u *User) Type() string { return "user" }
|
|
|
|
func (u *User) Read(ctx context.Context) ([]byte, error) {
|
|
var readUser *user.User
|
|
var e error
|
|
if u.Name != "" {
|
|
readUser, e = user.Lookup(u.Name)
|
|
}
|
|
if u.UID >= 0 {
|
|
readUser, e = user.LookupId(strconv.Itoa(u.UID))
|
|
}
|
|
|
|
if e != nil {
|
|
panic(e)
|
|
}
|
|
|
|
u.Name = readUser.Username
|
|
u.UID, _ = strconv.Atoi(readUser.Uid)
|
|
if readGroup, groupErr := user.LookupGroupId(readUser.Gid); groupErr == nil {
|
|
u.Group = readGroup.Name
|
|
} else {
|
|
panic(groupErr)
|
|
}
|
|
u.Home = readUser.HomeDir
|
|
u.Gecos = readUser.Name
|
|
|
|
return yaml.Marshal(u)
|
|
}
|