import dataclasses from dataclasses import dataclass, field from typing import List, Tuple from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import _proxmox_request, ProxmoxAuthInfo @dataclass(frozen=True) class ProxmoxACL: path: str role: str propagate: bool = True user: str = None group: str = None token: str = None def get_acls(auth_info: ProxmoxAuthInfo) -> List['ProxmoxACL']: acl_answer = _proxmox_request('get', '/access/acl', auth_info).json() return list(map( lambda r: ProxmoxACL(r['path'], r['roleid'], r['propagate'], (r['ugid'] if (r['type'] == 'user') else None), (r['ugid'] if (r['type'] == 'group') else None), (r['ugid'] if (r['type'] == 'token') else None)), acl_answer['data'] )) def set_acl(auth_info: ProxmoxAuthInfo, acl: ProxmoxACL, dry_run: bool, state: str = 'present') -> Tuple[dict, dict]: existing_acls = get_acls(auth_info) # find existing acl matching the specified one try: existing_acl = [x for x in existing_acls if x == acl][0] except: existing_acl = None if state == 'present': acl_spec = _acl_to_dict(acl) | { 'propagate': "1" if acl.propagate else "0" } if not dry_run: acl_res = _proxmox_request('put', '/access/acl', auth_info, data=acl_spec) acl_res.raise_for_status() if acl_res.ok: new_acl = acl else: new_acl = acl elif state == 'exact': # Also match on propagate and remove ACLs which match in all fields except propagation pass else: # ACL to be removed if not dry_run: acl_spec = _acl_to_dict(acl) | { 'delete': 1 } acl_res = _proxmox_request('put', '/access/acl', auth_info, data=acl_spec) acl_res.raise_for_status() if acl_res.ok: new_acl = None else: new_acl = None return dataclasses.asdict(existing_acl) if existing_acl else None, dataclasses.asdict(new_acl) if new_acl else None def _acl_to_dict(acl: ProxmoxACL) -> dict: acl_spec = { 'path': acl.path, 'roles': acl.role, } if acl.user: acl_spec['users'] = acl.user if acl.group: acl_spec['groups'] = acl.group if acl.token: acl_spec['tokens'] = acl.token return acl_spec