Add UID and GID min/max keys (#81770)

Fixes: #72183
pull/83291/merge
skupfer 4 months ago committed by GitHub
parent 6bf6844a1c
commit 20465ba11a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -0,0 +1,3 @@
minor_changes:
- Add ``uid_min``, ``uid_max`` to the user plugin to overwrite the defaults provided by the ``/etc/login.defs`` file (https://github.com/ansible/ansible/pull/81770).
- Add ``gid_min``, ``gid_max`` to the group plugin to overwrite the defaults provided by the ``/etc/login.defs`` file (https://github.com/ansible/ansible/pull/81770).

@ -62,6 +62,22 @@ options:
type: bool type: bool
default: no default: no
version_added: "2.8" version_added: "2.8"
gid_min:
description:
- Sets the GID_MIN value for group creation.
- Overwrites /etc/login.defs default value.
- Currently supported on Linux. Does nothing when used with other platforms.
- Requires O(local) is omitted or V(False).
type: int
version_added: "2.18"
gid_max:
description:
- Sets the GID_MAX value for group creation.
- Overwrites /etc/login.defs default value.
- Currently supported on Linux. Does nothing when used with other platforms.
- Requires O(local) is omitted or V(False).
type: int
version_added: "2.18"
extends_documentation_fragment: action_common_attributes extends_documentation_fragment: action_common_attributes
attributes: attributes:
check_mode: check_mode:
@ -151,6 +167,14 @@ class Group(object):
self.system = module.params['system'] self.system = module.params['system']
self.local = module.params['local'] self.local = module.params['local']
self.non_unique = module.params['non_unique'] self.non_unique = module.params['non_unique']
self.gid_min = module.params['gid_min']
self.gid_max = module.params['gid_max']
if self.local:
if self.gid_min is not None:
module.fail_json(msg="'gid_min' can not be used with 'local'")
if self.gid_max is not None:
module.fail_json(msg="'gid_max' can not be used with 'local'")
def execute_command(self, cmd): def execute_command(self, cmd):
return self.module.run_command(cmd) return self.module.run_command(cmd)
@ -184,6 +208,12 @@ class Group(object):
cmd.append('-o') cmd.append('-o')
elif key == 'system' and kwargs[key] is True: elif key == 'system' and kwargs[key] is True:
cmd.append('-r') cmd.append('-r')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -292,6 +322,12 @@ class SunOS(Group):
cmd.append(str(kwargs[key])) cmd.append(str(kwargs[key]))
if self.non_unique: if self.non_unique:
cmd.append('-o') cmd.append('-o')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -323,6 +359,12 @@ class AIX(Group):
cmd.append('id=' + str(kwargs[key])) cmd.append('id=' + str(kwargs[key]))
elif key == 'system' and kwargs[key] is True: elif key == 'system' and kwargs[key] is True:
cmd.append('-a') cmd.append('-a')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -368,6 +410,12 @@ class FreeBsdGroup(Group):
cmd.append(str(self.gid)) cmd.append(str(self.gid))
if self.non_unique: if self.non_unique:
cmd.append('-o') cmd.append('-o')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
return self.execute_command(cmd) return self.execute_command(cmd)
def group_mod(self, **kwargs): def group_mod(self, **kwargs):
@ -492,6 +540,12 @@ class OpenBsdGroup(Group):
cmd.append(str(self.gid)) cmd.append(str(self.gid))
if self.non_unique: if self.non_unique:
cmd.append('-o') cmd.append('-o')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -538,6 +592,12 @@ class NetBsdGroup(Group):
cmd.append(str(self.gid)) cmd.append(str(self.gid))
if self.non_unique: if self.non_unique:
cmd.append('-o') cmd.append('-o')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -578,6 +638,14 @@ class BusyBoxGroup(Group):
if self.system: if self.system:
cmd.append('-S') cmd.append('-S')
if self.gid_min is not None:
cmd.append('-K')
cmd.append('GID_MIN=' + str(self.gid_min))
if self.gid_max is not None:
cmd.append('-K')
cmd.append('GID_MAX=' + str(self.gid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -626,6 +694,8 @@ def main():
system=dict(type='bool', default=False), system=dict(type='bool', default=False),
local=dict(type='bool', default=False), local=dict(type='bool', default=False),
non_unique=dict(type='bool', default=False), non_unique=dict(type='bool', default=False),
gid_min=dict(type='int'),
gid_max=dict(type='int'),
), ),
supports_check_mode=True, supports_check_mode=True,
required_if=[ required_if=[

@ -275,6 +275,23 @@ options:
- Currently supported on AIX, Linux, NetBSD, OpenBSD. - Currently supported on AIX, Linux, NetBSD, OpenBSD.
type: int type: int
version_added: "2.18" version_added: "2.18"
uid_min:
description:
- Sets the UID_MIN value for user creation.
- Overwrites /etc/login.defs default value.
- Currently supported on Linux. Does nothing when used with other platforms.
- Requires O(local) is omitted or V(False).
type: int
version_added: "2.18"
uid_max:
description:
- Sets the UID_MAX value for user creation.
- Overwrites /etc/login.defs default value.
- Currently supported on Linux. Does nothing when used with other platforms.
- Requires O(local) is omitted or V(False).
type: int
version_added: "2.18"
extends_documentation_fragment: action_common_attributes extends_documentation_fragment: action_common_attributes
attributes: attributes:
check_mode: check_mode:
@ -595,9 +612,16 @@ class User(object):
self.password_expire_warn = module.params['password_expire_warn'] self.password_expire_warn = module.params['password_expire_warn']
self.umask = module.params['umask'] self.umask = module.params['umask']
self.inactive = module.params['password_expire_account_disable'] self.inactive = module.params['password_expire_account_disable']
self.uid_min = module.params['uid_min']
self.uid_max = module.params['uid_max']
if self.umask is not None and self.local: if self.local:
module.fail_json(msg="'umask' can not be used with 'local'") if self.umask is not None:
module.fail_json(msg="'umask' can not be used with 'local'")
if self.uid_min is not None:
module.fail_json(msg="'uid_min' can not be used with 'local'")
if self.uid_max is not None:
module.fail_json(msg="'uid_max' can not be used with 'local'")
if module.params['groups'] is not None: if module.params['groups'] is not None:
self.groups = ','.join(module.params['groups']) self.groups = ','.join(module.params['groups'])
@ -798,6 +822,14 @@ class User(object):
if self.system: if self.system:
cmd.append('-r') cmd.append('-r')
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
cmd.append(self.name) cmd.append(self.name)
(rc, out, err) = self.execute_command(cmd) (rc, out, err) = self.execute_command(cmd)
if not self.local or rc != 0: if not self.local or rc != 0:
@ -1465,6 +1497,14 @@ class FreeBsdUser(User):
else: else:
cmd.append(str(calendar.timegm(self.expires))) cmd.append(str(calendar.timegm(self.expires)))
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
# system cannot be handled currently - should we error if its requested? # system cannot be handled currently - should we error if its requested?
# create the user # create the user
(rc, out, err) = self.execute_command(cmd) (rc, out, err) = self.execute_command(cmd)
@ -1718,6 +1758,13 @@ class OpenBSDUser(User):
if self.inactive is not None: if self.inactive is not None:
cmd.append('-f') cmd.append('-f')
cmd.append(self.inactive) cmd.append(self.inactive)
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -1904,6 +1951,14 @@ class NetBSDUser(User):
cmd.append('-K') cmd.append('-K')
cmd.append('UMASK=' + self.umask) cmd.append('UMASK=' + self.umask)
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
cmd.append(self.name) cmd.append(self.name)
return self.execute_command(cmd) return self.execute_command(cmd)
@ -2112,6 +2167,13 @@ class SunOS(User):
if self.inactive is not None: if self.inactive is not None:
cmd.append('-f') cmd.append('-f')
cmd.append(self.inactive) cmd.append(self.inactive)
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
cmd.append(self.name) cmd.append(self.name)
@ -2722,6 +2784,13 @@ class AIX(User):
if self.inactive is not None: if self.inactive is not None:
cmd.append('-f') cmd.append('-f')
cmd.append(self.inactive) cmd.append(self.inactive)
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
cmd.append(self.name) cmd.append(self.name)
(rc, out, err) = self.execute_command(cmd) (rc, out, err) = self.execute_command(cmd)
@ -3059,6 +3128,14 @@ class BusyBox(User):
if self.system: if self.system:
cmd.append('-S') cmd.append('-S')
if self.uid_min is not None:
cmd.append('-K')
cmd.append('UID_MIN=' + str(self.uid_min))
if self.uid_max is not None:
cmd.append('-K')
cmd.append('UID_MAX=' + str(self.uid_max))
cmd.append(self.name) cmd.append(self.name)
rc, out, err = self.execute_command(cmd) rc, out, err = self.execute_command(cmd)
@ -3204,6 +3281,8 @@ def main():
role=dict(type='str'), role=dict(type='str'),
umask=dict(type='str'), umask=dict(type='str'),
password_expire_account_disable=dict(type='int', no_log=False), password_expire_account_disable=dict(type='int', no_log=False),
uid_min=dict(type='int'),
uid_max=dict(type='int'),
), ),
supports_check_mode=True, supports_check_mode=True,
) )

@ -16,4 +16,10 @@
# You should have received a copy of the GNU General Public License # You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>. # along with Ansible. If not, see <http://www.gnu.org/licenses/>.
- name: skip broken distros
meta: end_host
when: ansible_distribution == 'Alpine'
- import_tasks: tests.yml - import_tasks: tests.yml
- import_tasks: test_create_group_min_max.yml
when: ansible_facts.system == 'Linux'

@ -0,0 +1,73 @@
---
- name: create a group with a specific gid
group:
name: testgroupone
gid: 8000
state: present
register: group_test0_1
- name: create another group without a specific gid
group:
name: testgrouptwo
state: present
register: group_test0_2
- name: show that the last group gets an id higher than the previous highest one
assert:
that:
group_test0_1.gid < group_test0_2.gid
- name: create a group within gid_max range
group:
name: testgroupthree
gid_max: 1999
state: present
register: group_test0_3
- name: assert that a group with gid_max gets a lower gid
assert:
that:
group_test0_2.gid > group_test0_3.gid
- name: proof of range limits
block:
- name: create group 1 within min 1500 and max 1501
group:
name: testgroupfour
gid_min: 1500
gid_max: 1501
state: present
register: group_test0_4
- name: create group 2 within min 1500 and max 1501
group:
name: testgroupfive
gid_min: 1500
gid_max: 1501
state: present
register: group_test0_5
- name: create group 3 within min 1500 and max 1501 and show that the range applies
group:
name: testgroupsix
gid_min: 1500
gid_max: 1501
state: present
register: group_test0_6
failed_when: not group_test0_6.failed
- name: show that creating a group by setting both gid_min and local is not possible
group:
name: gidminlocalgroup_test_1
gid_min: 1000
local: true
register: gidminlocalgroup_test_1
failed_when: not gidminlocalgroup_test_1.failed
- name: show that creating a group by setting both gid_max and local is not possible
group:
name: gidmaxlocalgroup_test_1
gid_max: 2000
local: true
register: gidmaxlocalgroup_test_1
failed_when: not gidmaxlocalgroup_test_1.failed

@ -43,3 +43,5 @@
- import_tasks: test_umask.yml - import_tasks: test_umask.yml
when: ansible_facts.system == 'Linux' when: ansible_facts.system == 'Linux'
- import_tasks: test_inactive_new_account.yml - import_tasks: test_inactive_new_account.yml
- import_tasks: test_create_user_min_max.yml
when: ansible_facts.system == 'Linux'

@ -0,0 +1,73 @@
---
- name: create a user with a specific uid
user:
name: testuserone
uid: 8000
state: present
register: user_test0_1
- name: create another user without a specific uid
user:
name: testusertwo
state: present
register: user_test0_2
- name: show that the last user gets an id higher than the previous highest one
assert:
that:
user_test0_1.uid < user_test0_2.uid
- name: create a user within max range
user:
name: testuserthree
uid_max: 1999
state: present
register: user_test0_3
- name: assert that user with uid_max gets a lower uid
assert:
that:
user_test0_2.uid > user_test0_3.uid
- name: proof of range limits
block:
- name: create user 1 within min 1500 and max 1501
user:
name: testuserfour
uid_min: 1500
uid_max: 1501
state: present
register: user_test0_4
- name: create user 2 within min 1500 and max 1501
user:
name: testuserfive
uid_min: 1500
uid_max: 1501
state: present
register: user_test0_5
- name: create user 3 within min 1500 and max 1501 and show that the range applies
user:
name: testusersix
uid_min: 1500
uid_max: 1501
state: present
register: user_test0_6
failed_when: not user_test0_6.failed
- name: show that creating a group by setting both uid_min and local is not possible
user:
name: uidminlocaluser_test_1
uid_min: 1000
local: true
register: uidminlocaluser_test_1
failed_when: not uidminlocaluser_test_1.failed
- name: show that creating a group by setting both uid_max and local is not possible
user:
name: uidmaxlocaluser_test_1
uid_max: 2000
local: true
register: uidmaxlocaluser_test_1
failed_when: not uidmaxlocaluser_test_1.failed
Loading…
Cancel
Save