Skip to content

Commit

Permalink
Merge pull request #52 from gwbischof/users_group
Browse files Browse the repository at this point in the history
User-group modules
  • Loading branch information
pescobar authored Jun 11, 2024
2 parents 4cbcb62 + 988f0a3 commit 7b74b88
Show file tree
Hide file tree
Showing 4 changed files with 709 additions and 5 deletions.
11 changes: 10 additions & 1 deletion plugins/modules/guacamole_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,11 @@
- Should we enable sftp transfers for this connection?
type: bool
read_only:
description:
- True if connection should be read-only.
type: bool
sftp_port:
description:
- Port to use for sftp
Expand Down Expand Up @@ -336,6 +341,7 @@
username: vnc_user
password: vnc_pass
sftp_enable: true
read_only: false
sftp_port: 22
sftp_hostname: 192.168.11.11
sftp_server_alive_interval: 10
Expand Down Expand Up @@ -417,6 +423,7 @@ def guacamole_populate_connection_payload(module_params):
"parameters": {
"enable-sftp": module_params['sftp_enable'],
"sftp-directory": module_params['sftp_default_upload_directory'],
"read-only": module_params['read_only']
},
"attributes": {
"guacd-encryption": module_params['guacd_encryption'],
Expand Down Expand Up @@ -447,7 +454,8 @@ def guacamole_populate_connection_payload(module_params):
"sftp_root_directory",
"disable_copy",
"disable_paste",
"cursor"
"cursor",
"read_only"
)
guacamole_add_parameter(payload, module_params, parameters)

Expand Down Expand Up @@ -599,6 +607,7 @@ def main():
guacd_hostname=dict(type='str', required=False),
guacd_port=dict(type='int', required=False),
guacd_encryption=dict(type='str', required=False),
read_only=dict(type='bool', default=False),
)

result = dict(changed=False, msg='', diff={},
Expand Down
7 changes: 3 additions & 4 deletions plugins/modules/guacamole_connections_group.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,6 @@
URL_DELETE_CONNECTIONS_GROUP = URL_UPDATE_CONNECTIONS_GROUP



def guacamole_populate_connections_group_payload(module_params):
"""
Populate the json that we send to the guaccamole API to create new connections group
Expand All @@ -174,7 +173,7 @@ def guacamole_populate_connections_group_payload(module_params):
return payload


def guacamole_add_connections_group(base_url, validate_certs, datasource, auth_token, payload):
def guacamole_add_connections_group(base_url, validate_certs, datasource, auth_token, payload):
"""
Add a new connections group to the guacamole server.
"""
Expand Down Expand Up @@ -386,7 +385,7 @@ def main():
# if the group has child connections and force_deletion=false fail and exit
else:
module.fail_json(
msg="Won't delete a group with child connections unless force_deletion=True"
msg="Won't delete a group with child connections unless force_deletion=True"
)

# if the group to delete doesn't exists we just print a message
Expand All @@ -408,7 +407,7 @@ def main():

# check if something changed (idempotence)
if guacamole_connections_groups_before != guacamole_connections_groups_after:
result['changed'] = True
result['changed'] = True

# return connections_group_info{} for the added/updated/deleted connections group
if module.params.get('state') == 'present':
Expand Down
280 changes: 280 additions & 0 deletions plugins/modules/guacamole_user_group_users.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,280 @@
#!/usr/bin/python

# Copyright: (c) 2020, Pablo Escobar <[email protected]>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

from __future__ import absolute_import, division, print_function
import json

from ansible.module_utils.basic import AnsibleModule
from ansible.module_utils.urls import open_url
from ansible_collections.scicore.guacamole.plugins.module_utils.guacamole import GuacamoleError, \
guacamole_get_token
__metaclass__ = type

ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}

DOCUMENTATION = '''
---
module: guacamole_user_group_users
short_description: Administer guacamole user-group users using the rest API
version_added: "2.9"
description:
- "Add or remove guacamole connections groups."
options:
base_url:
description:
- Url to access the guacamole API
required: true
aliases: ['url']
type: str
auth_username:
description:
- Guacamole admin user to login to the API
required: true
type: str
auth_password:
description:
- Guacamole admin user password to login to the API
required: true
type: str
validate_certs:
description:
- Validate ssl certs?
default: true
type: bool
users:
description:
- Dictionary that maps user-groups to a list of users.
type: dict
elements: str
state:
description:
- Create, delete or sync the user-group members.
default: 'present'
type: str
choices:
- present
- absent
- sync
author:
- Pablo Escobar Lopez (@pescobar)
- Garrett Bischof (@gwbischof)
- Robert Schaffer (@RobertSchaffer1)
'''

EXAMPLES = '''
- name: Assign user 'u1' to user group 'users1'
scicore.guacamole.guacamole_user_group_users:
base_url: http://localhost/guacamole
auth_username: guacadmin
auth_password: guacadmin
users:
"{{ { 'users1': ['u1'] } }}"
state: present
- name: Remove user 'u1' from user group 'users1'
scicore.guacamole.guacamole_user_group_users:
base_url: http://localhost/guacamole
auth_username: guacadmin
auth_password: guacadmin
users:
"{{ { 'users1': ['u1'] } }}"
state: absent
- name: Assign user 'u1' to user group 'users1', and remove any other users from 'users1'.
scicore.guacamole.guacamole_user_group_users:
base_url: http://localhost/guacamole
auth_username: guacadmin
auth_password: guacadmin
users:
"{{ { 'users1': ['u1'] } }}"
state: sync
'''

RETURN = '''
message:
description: Some extra info about what the module did
type: str
returned: always
'''

URL_GET_GROUP_MEMBERS = "{url}/api/session/data/{datasource}/userGroups/{group_name}/memberUsers?token={token}"
URL_UPDATE_USERS_IN_GROUP = URL_GET_GROUP_MEMBERS


def guacamole_get_user_group_users(base_url, validate_certs, datasource, auth_token, group_name):
"""
Returns a dict of dicts.
Each dict provides the details for one of the users groups defined in guacamole
"""

url_get_users_group_permissions = URL_GET_GROUP_MEMBERS.format(
url=base_url, datasource=datasource, token=auth_token, group_name=group_name)

try:
group_permissions = json.load(open_url(url_get_users_group_permissions, method='GET',
validate_certs=validate_certs))
except ValueError as e:
raise GuacamoleError(
'API returned invalid JSON when trying to obtain group permissions from %s: %s'
% (url_get_users_group_permissions, str(e)))
except Exception as e:
raise GuacamoleError('Could not obtain group permissions from %s: %s'
% (url_get_users_group_permissions, str(e)))

return group_permissions


def guacamole_update_users_in_group(base_url, validate_certs, datasource, auth_token, group_name, user, action):
"""
Add or remove a user to a group.
Action must be "add" or "remove"
"""

if action not in ['add', 'remove']:
raise GuacamoleError("action must be 'add' or 'remove'")

url_update_users_in_group = URL_UPDATE_USERS_IN_GROUP.format(
url=base_url, datasource=datasource, token=auth_token, group_name=group_name)

payload = [{
"op": action,
"path": '/',
"value": user,
}]

try:
headers = {'Content-Type': 'application/json'}
open_url(url_update_users_in_group, method='PATCH', validate_certs=validate_certs, headers=headers,
data=json.dumps(payload))
except Exception as e:
raise GuacamoleError('Could not update users for group %s in url %s. Error msg: %s'
% (group_name, url_update_users_in_group, str(e)))


def main():

# define the available arguments/parameters that a user can pass to
# the module
module_args = dict(
base_url=dict(type='str', aliases=['url'], required=True),
auth_username=dict(type='str', required=True),
auth_password=dict(type='str', required=True, no_log=True),
validate_certs=dict(type='bool', default=True),
users=dict(type='dict', default={}),
state=dict(type='str', choices=['absent', 'present', 'sync'], default='present')
)

result = dict(changed=False, msg='')

module = AnsibleModule(
argument_spec=module_args,
supports_check_mode=False
)

# Obtain access token, initialize API
try:
guacamole_token = guacamole_get_token(
base_url=module.params.get('base_url'),
auth_username=module.params.get('auth_username'),
auth_password=module.params.get('auth_password'),
validate_certs=module.params.get('validate_certs'),
)
except GuacamoleError as e:
module.fail_json(msg=str(e))

users = module.params.get('users')

# Add users to user-group.
if module.params.get('state') in {'present', 'sync'}:
for group_name, usernames in users.items():

# Check the existing users for the user group.
try:
existing_users = set(guacamole_get_user_group_users(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
auth_token=guacamole_token['authToken'],
group_name=group_name
))
except GuacamoleError as e:
module.fail_json(msg=str(e))

# Find which users need to be added.
new_users = set(usernames) - existing_users

# Add new users to user-group.
for new_user in new_users:
try:
guacamole_update_users_in_group(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
auth_token=guacamole_token['authToken'],
group_name=group_name,
user=new_user,
action='add',
)
except GuacamoleError as e:
module.fail_json(msg=str(e))

result['changed'] = True

# Remove users from user group.
if module.params.get('state') in {'absent', 'sync'}:

for group_name, usernames in users.items():

# Find which users need to be removed.
existing_users = set(guacamole_get_user_group_users(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
auth_token=guacamole_token['authToken'],
group_name=group_name
))
if module.params.get('state') == 'absent':
remove_users = set(usernames) & existing_users
else:
remove_users = existing_users - set(usernames)

# Remove users.
for remove_user in remove_users:
try:
guacamole_update_users_in_group(
base_url=module.params.get('base_url'),
validate_certs=module.params.get('validate_certs'),
datasource=guacamole_token['dataSource'],
auth_token=guacamole_token['authToken'],
group_name=group_name,
user=remove_user,
action='remove',
)
except GuacamoleError as e:
module.fail_json(msg=str(e))

result['changed'] = True
module.exit_json(**result)


if __name__ == '__main__':
main()
Loading

0 comments on commit 7b74b88

Please sign in to comment.