Optimized logic for user generation

This commit is contained in:
Kevin Veen-Birkenbach 2025-07-02 15:20:55 +02:00
parent cb6fbba8f4
commit 9d1b44319c
No known key found for this signature in database
GPG Key ID: 44D8F11FD62F878E
2 changed files with 82 additions and 63 deletions

View File

@ -9,7 +9,7 @@ from collections import OrderedDict
def build_users(defs, primary_domain, start_id, become_pwd): def build_users(defs, primary_domain, start_id, become_pwd):
""" """
Build user entries with auto-incremented uid/gid and default username/email. Build user entries with auto-incremented uid/gid, default username/email, and optional description.
Args: Args:
defs (OrderedDict): Keys are user IDs, values are dicts with optional overrides. defs (OrderedDict): Keys are user IDs, values are dicts with optional overrides.
@ -19,16 +19,62 @@ def build_users(defs, primary_domain, start_id, become_pwd):
Returns: Returns:
OrderedDict: Merged user definitions with full fields. OrderedDict: Merged user definitions with full fields.
Raises:
ValueError: If duplicate override uids/gids or conflicts in generated values.
""" """
users = OrderedDict() users = OrderedDict()
next_id = start_id used_uids = set()
used_gids = set()
# Pre-collect any provided uids/gids and check for duplicates
for key, overrides in defs.items():
if 'uid' in overrides:
uid = overrides['uid']
if uid in used_uids:
raise ValueError(f"Duplicate uid {uid} for user '{key}'")
used_uids.add(uid)
if 'gid' in overrides:
gid = overrides['gid']
if gid in used_gids:
raise ValueError(f"Duplicate gid {gid} for user '{key}'")
used_gids.add(gid)
next_free = start_id
def allocate_free_id():
nonlocal next_free
# find next free id not in used_uids
while next_free in used_uids:
next_free += 1
free = next_free
used_uids.add(free)
used_gids.add(free)
next_free += 1
return free
# Build entries
for key, overrides in defs.items(): for key, overrides in defs.items():
username = overrides.get('username', key) username = overrides.get('username', key)
email = overrides.get('email', f"{username}@{primary_domain}") email = overrides.get('email', f"{username}@{primary_domain}")
uid = overrides.get('uid', next_id) description = overrides.get('description')
gid = overrides.get('gid', next_id)
is_admin = overrides.get('is_admin', False) # UID assignment
if 'uid' in overrides:
uid = overrides['uid']
else:
uid = allocate_free_id()
# GID assignment
if 'gid' in overrides:
gid = overrides['gid']
else:
# if gid not provided, default to uid (and ensure uniqueness)
if uid in used_gids:
# already added in allocate_free_id or pre-collect
gid = uid
else:
gid = uid
used_gids.add(gid)
entry = { entry = {
'username': username, 'username': username,
@ -37,11 +83,30 @@ def build_users(defs, primary_domain, start_id, become_pwd):
'uid': uid, 'uid': uid,
'gid': gid 'gid': gid
} }
if is_admin: if description is not None:
entry['description'] = description
if overrides.get('is_admin', False):
entry['is_admin'] = True entry['is_admin'] = True
users[key] = entry users[key] = entry
next_id += 1
# Validate uniqueness of username, email, and gid
seen_usernames = set()
seen_emails = set()
seen_gids = set()
for key, entry in users.items():
un = entry['username']
em = entry['email']
gd = entry['gid']
if un in seen_usernames:
raise ValueError(f"Duplicate username '{un}' in merged users")
if em in seen_emails:
raise ValueError(f"Duplicate email '{em}' in merged users")
if gd in seen_gids:
raise ValueError(f"Duplicate gid '{gd}' in merged users")
seen_usernames.add(un)
seen_emails.add(em)
seen_gids.add(gd)
return users return users
@ -134,12 +199,16 @@ def main():
print(f"Error merging user definitions: {e}", file=sys.stderr) print(f"Error merging user definitions: {e}", file=sys.stderr)
sys.exit(1) sys.exit(1)
try:
users = build_users( users = build_users(
defs=user_defs, defs=user_defs,
primary_domain=primary_domain, primary_domain=primary_domain,
start_id=args.start_id, start_id=args.start_id,
become_pwd=become_pwd become_pwd=become_pwd
) )
except ValueError as e:
print(f"Error building user entries: {e}", file=sys.stderr)
sys.exit(1)
default_users = {'default_users': users} default_users = {'default_users': users}
plain_data = dictify(default_users) plain_data = dictify(default_users)

View File

@ -1,50 +0,0 @@
default_users:
administrator:
username: administrator
email: administrator@{{ primary_domain }}
password: '{{ ansible_become_password }}'
uid: 1001
gid: 1001
is_admin: true
blackhole:
username: blackhole
email: blackhole@{{ primary_domain }}
password: '{{ ansible_become_password }}'
uid: 1002
gid: 1002
crm:
username: contact
email: contact@{{ primary_domain }}
password: '{{ ansible_become_password }}'
uid: 1003
gid: 1003
bounce:
username: bounce
email: bounce@{{ primary_domain }}
password: '{{ ansible_become_password }}'
uid: 1004
gid: 1004
newsletter:
username: newsletter
email: newsletter@{{ primary_domain }}
password: '{{ ansible_become_password }}'
uid: 1005
gid: 1005
no-reply:
username: no-reply
email: no-reply@{{ primary_domain }}
password: '{{ ansible_become_password }}'
uid: 1006
gid: 1006
sld:
username: '{{ primary_domain.split(''.'')[0] }}'
email: '{{ primary_domain.split(''.'')[0] }}@{{ primary_domain }}'
password: '{{ ansible_become_password }}'
uid: 1007
gid: 1007
tld:
username: '{{ primary_domain.split(''.'')[1] }}'
email: '{{ primary_domain.split(''.'')[1] }}@{{ primary_domain }}'
password: '{{ ansible_become_password }}'
uid: 1008
gid: 1008