feat(ansible): support local user management
This commit is contained in:
parent
65cd1b9e01
commit
dac108cab5
3 changed files with 67 additions and 8 deletions
|
|
@ -1432,13 +1432,18 @@ func moduleUserWithClient(_ *Executor, client sshRunner, args map[string]any) (*
|
|||
name := getStringArg(args, "name", "")
|
||||
state := getStringArg(args, "state", "present")
|
||||
appendGroups := getBoolArg(args, "append", false)
|
||||
local := getBoolArg(args, "local", false)
|
||||
|
||||
if name == "" {
|
||||
return nil, mockError("moduleUserWithClient", "user: name required")
|
||||
}
|
||||
|
||||
if state == "absent" {
|
||||
cmd := sprintf("userdel -r %s 2>/dev/null || true", name)
|
||||
delCmd := "userdel"
|
||||
if local {
|
||||
delCmd = "luserdel"
|
||||
}
|
||||
cmd := sprintf("%s -r %s 2>/dev/null || true", delCmd, name)
|
||||
_, _, _, _ = client.Run(context.Background(), cmd)
|
||||
return &TaskResult{Changed: true}, nil
|
||||
}
|
||||
|
|
@ -1482,12 +1487,18 @@ func moduleUserWithClient(_ *Executor, client sshRunner, args map[string]any) (*
|
|||
// Try usermod first, then useradd
|
||||
addOptsStr := joinStrings(addOpts, " ")
|
||||
modOptsStr := joinStrings(modOpts, " ")
|
||||
addCmd := "useradd"
|
||||
modCmd := "usermod"
|
||||
if local {
|
||||
addCmd = "luseradd"
|
||||
modCmd = "lusermod"
|
||||
}
|
||||
var cmd string
|
||||
if addOptsStr == "" {
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 || useradd %s", name, name)
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 || %s %s", name, addCmd, name)
|
||||
} else {
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 && usermod %s %s || useradd %s %s",
|
||||
name, modOptsStr, name, addOptsStr, name)
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 && %s %s %s || %s %s %s",
|
||||
name, modCmd, modOptsStr, name, addCmd, addOptsStr, name)
|
||||
}
|
||||
|
||||
stdout, stderr, rc, err := client.Run(context.Background(), cmd)
|
||||
|
|
|
|||
19
modules.go
19
modules.go
|
|
@ -1389,13 +1389,18 @@ func (e *Executor) moduleUser(ctx context.Context, client sshExecutorClient, arg
|
|||
name := getStringArg(args, "name", "")
|
||||
state := getStringArg(args, "state", "present")
|
||||
appendGroups := getBoolArg(args, "append", false)
|
||||
local := getBoolArg(args, "local", false)
|
||||
|
||||
if name == "" {
|
||||
return nil, coreerr.E("Executor.moduleUser", "name required", nil)
|
||||
}
|
||||
|
||||
if state == "absent" {
|
||||
cmd := sprintf("userdel -r %s 2>/dev/null || true", name)
|
||||
delCmd := "userdel"
|
||||
if local {
|
||||
delCmd = "luserdel"
|
||||
}
|
||||
cmd := sprintf("%s -r %s 2>/dev/null || true", delCmd, name)
|
||||
_, _, _, _ = client.Run(ctx, cmd)
|
||||
return &TaskResult{Changed: true}, nil
|
||||
}
|
||||
|
|
@ -1439,12 +1444,18 @@ func (e *Executor) moduleUser(ctx context.Context, client sshExecutorClient, arg
|
|||
// Try usermod first, then useradd
|
||||
addOptsStr := join(" ", addOpts)
|
||||
modOptsStr := join(" ", modOpts)
|
||||
addCmd := "useradd"
|
||||
modCmd := "usermod"
|
||||
if local {
|
||||
addCmd = "luseradd"
|
||||
modCmd = "lusermod"
|
||||
}
|
||||
var cmd string
|
||||
if addOptsStr == "" {
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 || useradd %s", name, name)
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 || %s %s", name, addCmd, name)
|
||||
} else {
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 && usermod %s %s || useradd %s %s",
|
||||
name, modOptsStr, name, addOptsStr, name)
|
||||
cmd = sprintf("id %s >/dev/null 2>&1 && %s %s %s || %s %s %s",
|
||||
name, modCmd, modOptsStr, name, addCmd, addOptsStr, name)
|
||||
}
|
||||
|
||||
stdout, stderr, rc, err := client.Run(ctx, cmd)
|
||||
|
|
|
|||
|
|
@ -148,6 +148,43 @@ func TestModulesAdv_ModuleUser_Good_NoOptsUsesSimpleForm(t *testing.T) {
|
|||
assert.False(t, result.Failed)
|
||||
}
|
||||
|
||||
func TestModulesAdv_ModuleUser_Good_LocalModeUsesLocalCommands(t *testing.T) {
|
||||
e, mock := newTestExecutorWithMock("host1")
|
||||
mock.expectCommand(`id localuser >/dev/null 2>&1 && lusermod`, "", "", 0)
|
||||
|
||||
result, err := moduleUserWithClient(e, mock, map[string]any{
|
||||
"name": "localuser",
|
||||
"local": true,
|
||||
"shell": "/bin/zsh",
|
||||
"home": "/var/lib/localuser",
|
||||
"append": true,
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result.Changed)
|
||||
assert.False(t, result.Failed)
|
||||
assert.True(t, mock.containsSubstring("lusermod"))
|
||||
assert.True(t, mock.containsSubstring("luseradd"))
|
||||
assert.True(t, mock.containsSubstring("-s /bin/zsh"))
|
||||
assert.True(t, mock.containsSubstring("-d /var/lib/localuser"))
|
||||
}
|
||||
|
||||
func TestModulesAdv_ModuleUser_Good_LocalModeRemovesLocalUser(t *testing.T) {
|
||||
e, mock := newTestExecutorWithMock("host1")
|
||||
mock.expectCommand(`luserdel -r localuser`, "", "", 0)
|
||||
|
||||
result, err := moduleUserWithClient(e, mock, map[string]any{
|
||||
"name": "localuser",
|
||||
"local": true,
|
||||
"state": "absent",
|
||||
})
|
||||
|
||||
require.NoError(t, err)
|
||||
assert.True(t, result.Changed)
|
||||
assert.False(t, result.Failed)
|
||||
assert.True(t, mock.hasExecuted(`luserdel -r localuser`))
|
||||
}
|
||||
|
||||
func TestModulesAdv_ModuleUser_Bad_MissingName(t *testing.T) {
|
||||
e, _ := newTestExecutorWithMock("host1")
|
||||
mock := NewMockSSHClient()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue