Compare commits

..

8 Commits

9 changed files with 510 additions and 6 deletions

View File

@ -36,12 +36,12 @@ def set_acl(auth_info: ProxmoxAuthInfo, acl: ProxmoxACL, dry_run: bool, state: s
if state == 'present': if state == 'present':
acl_spec = _acl_to_dict(acl) | { acl_spec = _acl_to_dict(acl) | {
'propagate': acl.propagate 'propagate': "1" if acl.propagate else "0"
} }
if not dry_run: if not dry_run:
acl_res = _proxmox_request('put', f"/access/acl", auth_info, data=acl_spec) acl_res = _proxmox_request('put', '/access/acl', auth_info, data=acl_spec)
acl_res.raise_for_status() acl_res.raise_for_status()
if acl_res.ok and acl_res.json()['success'] == 1: if acl_res.ok:
new_acl = acl new_acl = acl
else: else:
new_acl = acl new_acl = acl

View File

@ -28,7 +28,9 @@ def set_realm_data(auth_info: ProxmoxAuthInfo, realm: str, config: dict[str, str
if existing_realm.ok: if existing_realm.ok:
existing_realm_data = existing_realm.json()['data'] existing_realm_data = existing_realm.json()['data']
if not dry_run: if not dry_run:
realm_res = _proxmox_request('put', f"/access/domains/{realm}", auth_info, data=config) put_args_denylist = ['type']
put_config = {k: v for k, v in config.items() if k not in put_args_denylist}
realm_res = _proxmox_request('put', f"/access/domains/{realm}", auth_info, data=put_config)
realm_res.raise_for_status() realm_res.raise_for_status()
else: else:
if not dry_run: if not dry_run:
@ -53,3 +55,8 @@ def set_realm_data(auth_info: ProxmoxAuthInfo, realm: str, config: dict[str, str
new_realm_data = None new_realm_data = None
return existing_realm_data, new_realm_data return existing_realm_data, new_realm_data
def do_realm_sync(auth_info: ProxmoxAuthInfo, realm: str, config: dict[str, str], dry_run: bool):
sync_config = config | {"dry-run": dry_run}
realm_sync = _proxmox_request('post', f"/access/domains/{realm}/sync", auth_info, data=sync_config)
return realm_sync.ok

View File

@ -0,0 +1,11 @@
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import _proxmox_request, ProxmoxAuthInfo
def get_nodes(auth_info: ProxmoxAuthInfo) -> [dict]:
node_answer = _proxmox_request('get', f"/nodes", auth_info).json()
return node_answer['data']
def get_node(auth_info: ProxmoxAuthInfo, node: str) -> [dict]:
node_answer = _proxmox_request('get', f"/nodes/{node}", auth_info).json()
return node_answer['data']

View File

@ -0,0 +1,13 @@
from typing import List, Tuple
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import _proxmox_request, ProxmoxAuthInfo
def get_pools(auth_info: ProxmoxAuthInfo) -> [str]:
pool_answer = _proxmox_request('get', f"/pools", auth_info).json()
return pool_answer['data']
def get_pool(auth_info: ProxmoxAuthInfo, pool: str) -> [dict]:
pool_answer = _proxmox_request('get', f"/pools/{pool}", auth_info).json()
return pool_answer['data']

View File

@ -81,7 +81,7 @@ options:
If the access control list should be present, absent or exact. When state is exact, If the access control list should be present, absent or exact. When state is exact,
the value of `propagate` is also considered, and if an existing access control rule is found the value of `propagate` is also considered, and if an existing access control rule is found
which only differs in the value of `propagate`, the old rule is removed by the module, which only differs in the value of `propagate`, the old rule is removed by the module,
essentially replacing it. essentially replacing it.
type: str type: str
choices: [present, exact, absent] choices: [present, exact, absent]
default: present default: present
@ -100,7 +100,7 @@ EXAMPLES = r'''
propagate: true propagate: true
state: present state: present
- name: Configure an LDAP user to use their own VM - name: Configure an LDAP user to use their own VM
finallycoffee.proxmox.realm: finallycoffee.proxmox.acl:
proxmox_instance: https://my.proxmox-node.local:8006 proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent proxmox_api_secret: supersecuretokencontent

View File

@ -0,0 +1,127 @@
#!/usr/bin/python
# coding: utf-8
# (c) 2022, Johanna Dorothea Reichmann <transcaffeine@finally.coffee>
__metaclass__ = type
import dataclasses
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import *
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.proxmox_datacenter_group import *
DOCUMENTATION = r'''
---
module: group_info
author:
- Johanna Dorothea Reichmann (transcaffeine@finally.coffee)
requirements:
- python >= 3.9
short_description: Get all groups of a proxmox
description:
- "Lists all groups in proxmos"
options:
proxmox_instance:
description: Location of the proxmox API with scheme, domain name/ip and port, e.g. https://localhost:8006
type: str
required: true
proxmox_api_token_id:
description: The token ID containing username, realm and token name (format: user@realm!name)
type: str
required: true
proxmox_api_secret:
description: The secret
type: str
required: true
proxmox_api_verify_cert:
description: If the certificate presented for `proxmox_instance_url` should be verified
type: bool
required: false
default: true
group:
description: Group to retrieve information about. If left omitted, return all groups
type: str
required: false
'''
EXAMPLES = r'''
- name: Retrieve all groups
finallycoffee.proxmox.group_info:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
- name: Retrieve group information for group developers-realm
finallycoffee.proxmox.group_info:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
group: developers-realm
'''
RETURN = r'''
groups:
description: The retrieved groups
returned: When groups were found (matching the filter)
type: list
elements: dict[str, list[str]]
group:
description: The groups's name (`.name`) and members (`.members`)
returned: When a single group was queried
type: dict[str, list[str]]
'''
def main():
_ = dict
module = AnsibleModule(
argument_spec=_(
proxmox_instance=_(required=True, type='str'),
proxmox_api_token_id=_(required=True, type='str'),
proxmox_api_secret=_(type='str', required=True, no_log=True),
proxmox_api_verify_cert=_(type='bool', required=False, default=True),
group=_(required=False, type='str'),
),
supports_check_mode=True
)
result = _(
changed=False,
diff={},
message=''
)
groups = []
try:
groups = get_groups(ProxmoxAuthInfo(
module.params['proxmox_instance'],
module.params['proxmox_api_token_id'],
module.params['proxmox_api_secret'],
module.params['proxmox_api_verify_cert'],
))
except IOError as owie:
result['msg'] = owie
module.exit_json(**result)
result['groups'] = list(
map(lambda r: dataclasses.asdict(r),
filter(lambda r: r.name == module.params['group']
if module.params['group'] is not None
else True,
groups)
)
)
if module.params['group'] is not None:
result['group'] = dataclasses.asdict(
list(filter(lambda r: r.name == module.params['group'], groups))[0]
)
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,115 @@
#!/usr/bin/python
# coding: utf-8
# (c) 2022, Johanna Dorothea Reichmann <transcaffeine@finally.coffee>
__metaclass__ = type
import json
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import *
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.proxmox_node import *
DOCUMENTATION = r'''
---
module: node_info
author:
- Johanna Dorothea Reichmann (transcaffeine@finally.coffee)
requirements:
- python >= 3.9
short_description: Get information about all proxmox cluster nodes
description:
- "Equivalent to /api2/json/nodes, returns all available top-level information about all visible nodes"
options:
proxmox_instance:
description: Location of the proxmox API with scheme, domain name/ip and port, e.g. https://localhost:8006
type: str
required: true
proxmox_api_token_id:
description: The token ID containing username, realm and token name (format: user@realm!name)
type: str
required: true
proxmox_api_secret:
description: The secret
type: str
required: true
proxmox_api_verify_cert:
description: If the certificate presented for `proxmox_instance_url` should be verified
type: bool
required: false
default: true
node:
description: Node to retrieve information about.
type: str
required: true
'''
EXAMPLES = r'''
- name: Retrieve all nodes
finallycoffee.proxmox.node_info:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
- name: Retrieve info about node called "my_pm_host"
finallycoffee.proxmox.node_info:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
node: my_pm_hst
'''
RETURN = r'''
nodes:
description: All nodes present in the datacenter
returned: When nodes are visible to the API
type: list
elements: dict[str, str]
node:
description: Specific node information when queried for a single node
returned: When a single node was queried and found
type: dict[str, str]
'''
def main():
_ = dict
module = AnsibleModule(
argument_spec=_(
proxmox_instance=_(required=True, type='str'),
proxmox_api_token_id=_(required=True, type='str'),
proxmox_api_secret=_(type='str', required=True, no_log=True),
proxmox_api_verify_cert=_(type='bool', required=False, default=True),
node=_(required=False, type='str'),
),
supports_check_mode=True
)
result = _(
changed=False,
diff={},
message=''
)
nodes = []
try:
nodes = get_nodes(ProxmoxAuthInfo(
module.params['proxmox_instance'],
module.params['proxmox_api_token_id'],
module.params['proxmox_api_secret'],
module.params['proxmox_api_verify_cert'],
))
except IOError as owie:
result['msg'] = owie
module.exit_json(**result)
result['nodes'] = nodes
if module.params['node'] is not None:
result['node'] = list(filter(lambda n: n.name == module.params['node'], nodes))[0]
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,96 @@
#!/usr/bin/python
# coding: utf-8
# (c) 2022, Johanna Dorothea Reichmann <transcaffeine@finally.coffee>
__metaclass__ = type
import json
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import *
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.proxmox_pool import *
DOCUMENTATION = r'''
---
module: pool_info
author:
- Johanna Dorothea Reichmann (transcaffeine@finally.coffee)
requirements:
- python >= 3.9
short_description: Get information about all proxmox cluster nodes
description:
- "Equivalent to /api2/json/nodes, returns all available top-level information about all visible nodes"
options:
proxmox_instance:
description: Location of the proxmox API with scheme, domain name/ip and port, e.g. https://localhost:8006
type: str
required: true
proxmox_api_token_id:
description: The token ID containing username, realm and token name (format: user@realm!name)
type: str
required: true
proxmox_api_secret:
description: The secret
type: str
required: true
proxmox_api_verify_cert:
description: If the certificate presented for `proxmox_instance_url` should be verified
type: bool
required: false
default: true
'''
EXAMPLES = r'''
- name: Retrieve all resource pools
finallycoffee.proxmox.pool_info:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
'''
RETURN = r'''
pools:
description: All resource pools present in the datacenter
returned: When pools are visible (token has atleast Pool.Audit on each pool)
type: list
elements: str
'''
def main():
_ = dict
module = AnsibleModule(
argument_spec=_(
proxmox_instance=_(required=True, type='str'),
proxmox_api_token_id=_(required=True, type='str'),
proxmox_api_secret=_(type='str', required=True, no_log=True),
proxmox_api_verify_cert=_(type='bool', required=False, default=True),
),
supports_check_mode=True
)
result = _(
changed=False,
diff={},
message=''
)
pools = []
try:
pools = get_pools(ProxmoxAuthInfo(
module.params['proxmox_instance'],
module.params['proxmox_api_token_id'],
module.params['proxmox_api_secret'],
module.params['proxmox_api_verify_cert'],
))
except IOError as owie:
result['msg'] = owie
module.exit_json(**result)
result['pools'] = pools
module.exit_json(**result)
if __name__ == '__main__':
main()

View File

@ -0,0 +1,135 @@
#!/usr/bin/python
# coding: utf-8
# (c) 2022, Johanna Dorothea Reichmann <transcaffeine@finally.coffee>
__metaclass__ = type
import traceback
from ansible.module_utils.basic import AnsibleModule
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.common import *
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.proxmox_datacenter_realm import *
LIB_IMP_ERR = None
try:
from ansible_collections.finallycoffee.proxmox.plugins.module_utils.proxmox_datacenter_realm import do_realm_sync
HAS_LIB = True
except:
HAS_LIB = False
LIB_IMP_ERR = traceback.format_exc()
DOCUMENTATION = r'''
---
module: realm_sync
author:
- Johanna Dorothea Reichmann (transcaffeine@finally.coffee)
requirements:
- python >= 3.9
short_description: Ensures a realm is synchronized
description:
- "Allows synchronizing users, groups or both using the realm sync mechanism"
options:
proxmox_instance:
description: Location of the proxmox API with scheme, domain name/ip and port, e.g. https://localhost:8006
type: str
required: true
proxmox_api_token_id:
description: The token ID containing username, realm and token name (format: user@realm!name)
type: str
required: true
proxmox_api_secret:
description: The secret
type: str
required: true
proxmox_api_verify_cert:
description: If the certificate presented for `proxmox_instance_url` should be verified
type: bool
required: false
default: true
name:
description: Realm to schedule synchronize job for
type: str
required: true
config:
description: >-
Configuration for the synchronization. See
https://pve.proxmox.com/pve-docs/api-viewer/index.html#/access/domains/{realm}/sync
for a list of parameters
type: dict[str, str]
required: true
'''
EXAMPLES = r'''
- name: Sync only users on realm 'org_ldap', deleting users who can't be found amymore
finallycoffee.proxmox.realm_sync:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
realms: org_ldap
config:
enable-new: true
remove-vanished: entry
scope: users
- name: Sync groups and users and delete all ACLs on vanished groups and/or users
finallycoffee.proxmox.realm_sync:
proxmox_instance: https://my.proxmox-node.local:8006
promox_api_token_id: root@pam!token
proxmox_api_secret: supersecuretokencontent
realm: org_ldap
config:
enable-new: true
remove-vanished: acl;properties;entry
scope: both
'''
RETURN = r'''
'''
def main():
_ = dict
module = AnsibleModule(
argument_spec=_(
proxmox_instance=_(required=True, type='str'),
proxmox_api_token_id=_(required=True, type='str'),
proxmox_api_secret=_(type='str', required=True, no_log=True),
proxmox_api_verify_cert=_(type='bool', required=False, default=True),
name=_(required=True, type='str'),
config=_(required=True, type='dict')
),
supports_check_mode=True
)
result = _(
changed=False,
diff={},
message=''
)
try:
do_realm_sync(ProxmoxAuthInfo(
module.params['proxmox_instance'],
module.params['proxmox_api_token_id'],
module.params['proxmox_api_secret'],
module.params['proxmox_api_verify_cert'],
),
module.params['name'],
module.params['config'],
module.check_mode)
except IOError as owie:
result['msg'] = owie
module.exit_json(**result)
result['changed'] = True
module.exit_json(**result)
if __name__ == '__main__':
main()