From d611a9d79f45bf609906d9f4ecd806d5e0697017 Mon Sep 17 00:00:00 2001 From: Abhijeet Kasurde Date: Wed, 14 Aug 2024 20:14:37 -0700 Subject: [PATCH] Add user module * Added module to manage the user * tests Signed-off-by: Abhijeet Kasurde --- plugins/modules/user.py | 204 ++++++++++++++++++ .../integration/targets/user/tasks/create.yml | 147 +++++++++++++ tests/integration/targets/user/tasks/main.yml | 30 +++ .../integration/targets/user/tasks/update.yml | 56 +++++ 4 files changed, 437 insertions(+) create mode 100644 plugins/modules/user.py create mode 100644 tests/integration/targets/user/tasks/create.yml create mode 100644 tests/integration/targets/user/tasks/main.yml create mode 100644 tests/integration/targets/user/tasks/update.yml diff --git a/plugins/modules/user.py b/plugins/modules/user.py new file mode 100644 index 00000000..9e077e16 --- /dev/null +++ b/plugins/modules/user.py @@ -0,0 +1,204 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: Contributors to the Ansible project +# 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 + +__metaclass__ = type + +DOCUMENTATION = """ +--- +module: user +author: + - Nikhil Jain (@jainnikhil30) + - Abhijeet Kasurde (@akasurde) +short_description: Manage users in EDA controller +description: + - This module allows the user to create, update or delete users in a EDA controller. +version_added: '2.0.0' +options: + username: + description: + - The name of the user. + - 150 characters or fewer. + - Name can contain letters, digits and ('@', '.', '+', '-', '_') only. + type: str + required: true + new_username: + description: + - Setting this option will change the existing username. + type: str + first_name: + description: + - First name of the user. + type: str + last_name: + description: + - Last name of the user. + type: str + email: + description: + - Email address of the user. + type: str + password: + description: + - Write-only field used to change the password. + type: str + update_secrets: + description: + - V(true) will always change password if user specifies password, + even if API gives $encrypted$ for password. + - V(false) will only set the password if other values change too. + type: bool + default: true + state: + description: + - Desired state of the resource. + default: "present" + choices: ["present", "absent"] + type: str + is_superuser: + description: + - Make user as superuser. + default: false + type: bool +extends_documentation_fragment: + - ansible.eda.eda_controller.auths +""" + +EXAMPLES = """ +- name: Create EDA user + ansible.eda.user: + controller_host: https://my_eda_host/ + controller_username: admin + controller_password: MySuperSecretPassw0rd + username: "test_collection_user" + first_name: "Test Collection User" + last_name: "Test Collection User" + email: "test@test.com" + password: "test" + is_superuser: True + state: present + no_log: true + +- name: Delete user + ansible.eda.user: + controller_host: https://my_eda_host/ + controller_username: admin + controller_password: MySuperSecretPassw0rd + username: "test_collection_user" + state: absent + +- name: Update the username + ansible.eda.user: + username: "test_collection_user" + new_username: "test_collection_user_updated" + first_name: "Test Collection User" + last_name: "Test Collection User" + email: "test@test.com" + password: "test" +""" + + +RETURN = """ +id: + description: ID of the managed AWX token. + returned: when state is 'present' and successful + type: str + sample: "123" +""" + +from ansible.module_utils.basic import AnsibleModule + +from ..module_utils.arguments import AUTH_ARGSPEC +from ..module_utils.client import Client +from ..module_utils.controller import Controller +from ..module_utils.errors import EDAError + + +def main(): + argument_spec = dict( + username=dict(required=True), + new_username=dict(), + first_name=dict(), + last_name=dict(), + email=dict(), + password=dict(no_log=True), + is_superuser=dict(type="bool", default=False), + update_secrets=dict(type="bool", default=True), + state=dict(choices=["present", "absent"], default="present"), + ) + + argument_spec.update(AUTH_ARGSPEC) + + module = AnsibleModule(argument_spec=argument_spec, supports_check_mode=True) + + client = Client( + host=module.params.get("controller_host"), + username=module.params.get("controller_username"), + password=module.params.get("controller_password"), + timeout=module.params.get("request_timeout"), + validate_certs=module.params.get("validate_certs"), + ) + + controller = Controller(client, module) + user_endpoint = "users" + + # Extract the params + username = module.params.get("username") + new_username = module.params.get("new_username") + state = module.params.get("state") + is_superuser = module.params.get("is_superuser") + + ret = {} + + try: + user_type = controller.get_one_or_many(user_endpoint, name=username) + except EDAError as eda_err: + module.fail_json(msg=str(eda_err)) + + if state == "absent": + # If the state was absent we can let the module delete it if needed, the module will handle exiting from this + try: + ret = controller.delete_if_needed(user_type, endpoint=user_endpoint) + except EDAError as eda_err: + module.fail_json(msg=str(eda_err)) + module.exit_json(**ret) + + # User Data that will be sent for create/update + user_fields = {} + if new_username: + user_fields["username"] = new_username + elif user_type: + user_fields["username"] = controller.get_item_name(user_type) + elif username: + user_fields["username"] = username + + for field_name in ( + "first_name", + "last_name", + "email", + "password", + ): + field_value = module.params.get(field_name) + if field_value is not None: + user_fields[field_name] = field_value + + user_fields["is_superuser"] = is_superuser + + try: + ret = controller.create_or_update_if_needed( + existing_item=user_type, + new_item=user_fields, + endpoint=user_endpoint, + item_type="user", + ) + except EDAError as eda_err: + module.fail_json(msg=str(eda_err)) + module.exit_json(**ret) + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/user/tasks/create.yml b/tests/integration/targets/user/tasks/create.yml new file mode 100644 index 00000000..1885d7f7 --- /dev/null +++ b/tests/integration/targets/user/tasks/create.yml @@ -0,0 +1,147 @@ +--- +# Copyright: Contributors to the Ansible project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Create super user in check mode + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: true + state: present + check_mode: true + register: r + +- name: Check super user creation in check mode + assert: + that: + - r.changed + +- name: Create super user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: true + state: present + register: r + +- name: Check super user creation + assert: + that: + - r.changed + +- name: Create super user again + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: true + state: present + register: r + +- name: Check super user creation again + assert: + that: + - r.changed + +- name: Delete super user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + state: absent + register: r + +- name: Check super user deleted + assert: + that: + - r.changed + +- name: Create normal user in check mode + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: false + state: present + check_mode: true + register: r + +- name: Check normal user creation in check mode + assert: + that: + - r.changed + +- name: Create normal user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: false + state: present + register: r + +- name: Check normal user creation + assert: + that: + - r.changed + +- name: Create normal user again + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: false + state: present + register: r + +- name: Check normal user creation again + assert: + that: + - r.changed + +- name: Delete normal user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + state: absent + register: r + +- name: Check normal user deleted + assert: + that: + - r.changed diff --git a/tests/integration/targets/user/tasks/main.yml b/tests/integration/targets/user/tasks/main.yml new file mode 100644 index 00000000..dee345d8 --- /dev/null +++ b/tests/integration/targets/user/tasks/main.yml @@ -0,0 +1,30 @@ +--- +# Copyright: Contributors to the Ansible project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- block: + - name: Generate a random_string for the test + set_fact: + random_string: "{{ lookup('password', '/dev/null chars=ascii_letters length=16') }}" + when: random_string is not defined + + - name: Define variables for user + set_fact: + user_name: "test_user_{{ random_string }}" + first_name: "first_{{ random_string }}" + last_name: "last_{{ random_string }}" + email: "test_user_{{ random_string }}@example.com" + + - include_tasks: create.yml + - include_tasks: update.yml + always: + - name: Clean up - user + ansible.eda.project: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + name: "{{ item }}" + state: absent + loop: + - "{{ user_name }}" + ignore_errors: true diff --git a/tests/integration/targets/user/tasks/update.yml b/tests/integration/targets/user/tasks/update.yml new file mode 100644 index 00000000..1270d6e1 --- /dev/null +++ b/tests/integration/targets/user/tasks/update.yml @@ -0,0 +1,56 @@ +--- +# Copyright: Contributors to the Ansible project +# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) + +- name: Create super user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + first_name: "{{ first_name }}" + last_name: "{{ last_name }}" + email: "{{ email }}" + password: "{{ random_string }}" + is_superuser: true + state: present + register: r + +- name: Check super user creation + assert: + that: + - r.changed + +- name: Update super user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}" + new_username: "{{ user_name }}_new" + first_name: "{{ first_name }}_new" + last_name: "{{ last_name }}_new" + email: "new_{{ email }}" + password: "{{ random_string }}" + is_superuser: true + state: present + register: r + +- name: Check super user update + assert: + that: + - r.changed + +- name: Delete super user + ansible.eda.user: + controller_host: "{{ controller_host }}" + controller_username: "{{ controller_user }}" + validate_certs: "{{ validate_certs }}" + username: "{{ user_name }}_new" + state: absent + register: r + +- name: Check super user deleted + assert: + that: + - r.changed