diff --git a/lib/ansible/modules/network/avi/avi_user.py b/lib/ansible/modules/network/avi/avi_user.py new file mode 100644 index 00000000000..8963f9acee0 --- /dev/null +++ b/lib/ansible/modules/network/avi/avi_user.py @@ -0,0 +1,193 @@ +#!/usr/bin/python +""" +# Created on Aug 2, 2018 +# +# @author: Shrikant Chaudhari (shrikant.chaudhari@avinetworks.com) GitHub ID: gitshrikant +# +# module_check: supported +# +# This file is part of Ansible +# +# Ansible is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# +""" + +from __future__ import absolute_import, division, print_function +__metaclass__ = type + +ANSIBLE_METADATA = {'metadata_version': '1.1', + 'status': ['preview'], + 'supported_by': 'community'} + +DOCUMENTATION = ''' +--- +module: avi_user +author: Shrikant Chaudhari (@gitshrikant) +short_description: Avi User Module +description: + - This module can be used for creation, updation and deletion of a user. +version_added: 2.9 +requirements: [ avisdk ] +options: + state: + description: + - The state that should be applied on the entity. + default: present + choices: ["absent", "present"] + type: str + name: + description: + - Full name of the user. + required: true + type: str + obj_username: + description: + - Name that the user will supply when signing into Avi Vantage, such as jdoe or jdoe@avinetworks.com. + required: true + type: str + obj_password: + description: + - You may either enter a case-sensitive password in this field for the new or existing user. + required: true + type: str + email: + description: + - Email address of the user. This field is used when a user loses their password and requests to have it reset. See Password Recovery. + type: str + access: + description: + - Access settings (write, read, or no access) for each type of resource within Vantage. + type: list + is_superuser: + description: + - If the user will need to have the same privileges as the admin account, set it to true. + type: bool + is_active: + description: + - Activates the current user account. + type: bool + avi_api_update_method: + description: + - Default method for object update is HTTP PUT. + - Setting to patch will override that behavior to use HTTP PATCH. + default: put + choices: ["post", "put", "patch"] + type: str + avi_api_patch_op: + description: + - Patch operation to use when using avi_api_update_method as patch. + choices: ["add", "replace", "delete"] + type: str + user_profile_ref: + description: + - Refer user profile. + - This can also be full URI same as it comes in response payload + type: str + default_tenant_ref: + description: + - Default tenant reference. + - This can also be full URI same as it comes in response payload + default: /api/tenant?name=admin + type: str + + +extends_documentation_fragment: + - avi +''' + +EXAMPLES = ''' + - name: user creation + avi_user: + controller: "" + username: "" + password: "" + api_version: "" + name: "testuser" + obj_username: "testuser" + obj_password: "test123" + email: "test@abc.test" + access: + - role_ref: "/api/role?name=Tenant-Admin" + tenant_ref: "/api/tenant/admin#admin" + user_profile_ref: "/api/useraccountprofile?name=Default-User-Account-Profile" + is_active: true + is_superuser: true + default_tenant_ref: "/api/tenant?name=admin" + + - name: user creation + avi_user: + controller: "" + username: "" + password: "" + api_version: "" + name: "testuser" + obj_username: "testuser2" + obj_password: "password" + email: "testuser2@abc.test" + access: + - role_ref: "https://192.0.2.10/api/role?name=Tenant-Admin" + tenant_ref: "https://192.0.2.10/api/tenant/admin#admin" + user_profile_ref: "https://192.0.2.10/api/useraccountprofile?name=Default-User-Account-Profile" + is_active: true + is_superuser: true + default_tenant_ref: "https://192.0.2.10/api/tenant?name=admin" +''' + +RETURN = ''' +obj: + description: Avi REST resource + returned: success, changed + type: dict +''' + +from ansible.module_utils.basic import AnsibleModule + +try: + from ansible.module_utils.network.avi.avi import ( + avi_common_argument_spec, ansible_return, HAS_AVI) + from ansible.module_utils.network.avi.ansible_utils import ( + avi_ansible_api) +except ImportError: + HAS_AVI = False + + +def main(): + argument_specs = dict( + state=dict(default='present', + choices=['absent', 'present']), + name=dict(type='str', required=True), + obj_username=dict(type='str', required=True), + obj_password=dict(type='str', required=True, no_log=True), + access=dict(type='list',), + email=dict(type='str',), + is_superuser=dict(type='bool',), + is_active=dict(type='bool',), + avi_api_update_method=dict(default='put', + choices=['post', 'put', 'patch']), + avi_api_patch_op=dict(choices=['add', 'replace', 'delete']), + user_profile_ref=dict(type='str',), + default_tenant_ref=dict(type='str', default='/api/tenant?name=admin'), + ) + argument_specs.update(avi_common_argument_spec()) + module = AnsibleModule(argument_spec=argument_specs, supports_check_mode=True) + if not HAS_AVI: + return module.fail_json(msg=( + 'Avi python API SDK (avisdk>=17.1) or requests is not installed. ' + 'For more details visit https://github.com/avinetworks/sdk.')) + return avi_ansible_api(module, 'user', + set([])) + + +if __name__ == '__main__': + main() diff --git a/test/units/modules/network/avi/fixtures/avi_user.json b/test/units/modules/network/avi/fixtures/avi_user.json new file mode 100644 index 00000000000..85522c324a1 --- /dev/null +++ b/test/units/modules/network/avi/fixtures/avi_user.json @@ -0,0 +1,215 @@ +{ + "mock_create_res": { + "ansible_facts": { + "avi_api_context": { + "192.0.2.97:admin:None": { + "csrftoken": "qG23CCARDL3rh1KZ66XXPIeUYCUCOZ4q", + "session_id": "h5nynf9u9nompp5byai7vii2v8bbn9kd" + } + } + }, + "api_context": null, + "changed": true, + "invocation": { + "module_args": { + "access": [{ + "role_ref": "/api/role?name=Tenant-Admin", + "tenant_ref": "/api/tenant/********#********", + "all_tenants": false + }], + "api_context": null, + "api_version": "18.2.5", + "avi_api_update_method": "put", + "avi_credentials": null, + "avi_disable_session_cache_as_fact": false, + "avi_login_info": null, + "controller": "192.0.2.97", + "default_tenant_ref": "/api/tenant?name=********", + "email": "test@abc.com", + "is_active": true, + "is_superuser": true, + "name": "testuser", + "obj_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "obj_username": "testuser", + "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "state": "present", + "tenant": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "tenant_uuid": "", + "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile", + "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" + } + }, + "obj": { + "_last_modified": "1559736767460818", + "access": [{ + "all_tenants": false, + "role_ref": "https://192.0.2.97/api/tenant/********/role/role-ff851004-bd75-485b-87ec-2fe1d6a03fb9#Tenant-Admin", + "tenant_ref": "https://192.0.2.97/api/tenant/********#********" + }], + "default_tenant_ref": "https://192.0.2.97/api/tenant/********#********", + "email": "test@abc.com", + "full_name": "testuser", + "is_active": true, + "is_superuser": true, + "local": true, + "name": "testuser", + "obj_password": "", + "obj_username": "testuser", + "password": "", + "uid": 2004, + "url": "https://192.0.2.97/api/user/user-7087578f-4dfe-4e06-a153-495a91824a1d#testuser", + "user_profile_ref": "https://192.0.2.97/api/useraccountprofile/useraccountprofile-78063e7c-b443-48d6-b34c-5253ae1fcd2a#Default-User-Account-Profile", + "username": "testuser", + "uuid": "user-7087578f-4dfe-4e06-a153-495a91824a1d" + }, + "old_obj": null + }, + "mock_put_res": { + "obj": { + "username": "testuser", + "user_profile_ref": "https://192.0.2.97/api/useraccountprofile/useraccountprofile-546c5e88-6270-4ba1-9cfd-d0c755e68f47#Default-User-Account-Profile", + "name": "testuser", + "url": "https://192.0.2.97/api/user/user-ed10f328-bd92-4db2-bacd-0cf795fcbf8a#testuser", + "is_active": true, + "uuid": "user-ed10f328-bd92-4db2-bacd-0cf795fcbf8a", + "email": "newemail@abc.com", + "access": [{ + "tenant_ref": "https://192.0.2.97/api/tenant/tenant-57af0f3f-6f14-4657-8f32-9b289407752b#Test-Admin", + "all_tenants": false, + "role_ref": "https://192.0.2.97/api/tenant/********/role/role-b073ab0d-e1d0-4800-95ef-6ecf2c5ed7d1#Tenant-Admin" + }], + "is_superuser": true, + "obj_username": "testuser", + "full_name": "testuser", + "_last_modified": "1559802772203285", + "password": "", + "local": true, + "obj_password": "", + "default_tenant_ref": "https://192.0.2.97/api/tenant/********#********", + "uid": 2002 + }, + "changed": true, + "api_context": null, + "invocation": { + "module_args": { + "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile", + "api_version": "18.2.5", + "name": "testuser", + "state": "present", + "is_active": true, + "api_context": null, + "avi_disable_session_cache_as_fact": false, + "controller": "192.0.2.97", + "avi_api_patch_op": null, + "access": [{ + "tenant_ref": "/api/tenant?name=Test-Admin", + "all_tenants": false, + "role_ref": "/api/role?name=Tenant-Admin" + }], + "is_superuser": true, + "avi_credentials": null, + "email": "newemail@abc.com", + "default_tenant_ref": "/api/tenant?name=********", + "obj_username": "testuser", + "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "tenant_uuid": "", + "obj_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "avi_api_update_method": "put", + "tenant": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" + } + }, + "ansible_facts": { + "avi_api_context": { + "192.0.2.97:admin:None": { + "csrftoken": "Y7CET6zaIC9VZAzBqEW4cWo1N26jPg55", + "session_id": "364n7o0p3o5so63b9rzd47v6ehya6xg7" + } + } + }, + "old_obj": { + "username": "testuser", + "user_profile_ref": "https://192.0.2.97/api/useraccountprofile/useraccountprofile-546c5e88-6270-4ba1-9cfd-d0c755e68f47#Default-User-Account-Profile", + "name": "testuser", + "url": "https://192.0.2.97/api/user/user-ed10f328-bd92-4db2-bacd-0cf795fcbf8a#testuser", + "is_active": true, + "uuid": "user-ed10f328-bd92-4db2-bacd-0cf795fcbf8a", + "access": [{ + "tenant_ref": "https://192.0.2.97/api/tenant/tenant-57af0f3f-6f14-4657-8f32-9b289407752b#Test-Admin", + "all_tenants": false, + "role_ref": "https://192.0.2.97/api/tenant/********/role/role-b073ab0d-e1d0-4800-95ef-6ecf2c5ed7d1#Tenant-Admin" + }], + "is_superuser": true, + "full_name": "testuser", + "ui_property": "", + "password": "", + "local": true, + "email": "test@abc.com", + "default_tenant_ref": "https://192.0.2.97/api/tenant/********#********", + "uid": 2002 + } + }, + "mock_del_res": { + "ansible_facts": { + "avi_api_context": { + "192.0.2.97:admin:None": { + "csrftoken": "Vtkx9GeS2lsrld5yX83cmJqbZO3MAimb", + "session_id": "ix3t1dja8yzwb155de59viyn96hibn6b" + } + } + }, + "api_context": null, + "changed": true, + "invocation": { + "module_args": { + "access": [{ + "role_ref": "/api/role?name=Tenant-Admin", + "tenant_ref": "/api/tenant/********#********" + }], + "api_context": null, + "api_version": "18.2.5", + "avi_api_update_method": "put", + "avi_credentials": null, + "avi_disable_session_cache_as_fact": false, + "avi_login_info": null, + "controller": "192.0.2.97", + "default_tenant_ref": "/api/tenant?name=********", + "email": "test@abc.com", + "is_active": true, + "is_superuser": true, + "name": "testuser", + "obj_password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "obj_username": "testuser", + "password": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "state": "absent", + "tenant": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER", + "tenant_uuid": "", + "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile", + "username": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER" + } + }, + "obj": null, + "old_obj": { + "_last_modified": "1559803346264869", + "access": [{ + "all_tenants": false, + "role_ref": "https://192.0.2.97/api/tenant/********/role/role-b073ab0d-e1d0-4800-95ef-6ecf2c5ed7d1#Tenant-Admin", + "tenant_ref": "https://192.0.2.97/api/tenant/tenant-57af0f3f-6f14-4657-8f32-9b289407752b#Test-Admin" + }], + "default_tenant_ref": "https://192.0.2.97/api/tenant/********#********", + "email": "newemail@abc.com", + "full_name": "testuser", + "is_active": true, + "is_superuser": true, + "local": true, + "name": "testuser", + "password": "", + "ui_property": "", + "uid": 2002, + "url": "https://192.0.2.97/api/user/user-ed10f328-bd92-4db2-bacd-0cf795fcbf8a#testuser", + "user_profile_ref": "https://192.0.2.97/api/useraccountprofile/useraccountprofile-546c5e88-6270-4ba1-9cfd-d0c755e68f47#Default-User-Account-Profile", + "username": "testuser", + "uuid": "user-ed10f328-bd92-4db2-bacd-0cf795fcbf8a" + } + } +} diff --git a/test/units/modules/network/avi/test_avi_user.py b/test/units/modules/network/avi/test_avi_user.py new file mode 100644 index 00000000000..c4efb87ceac --- /dev/null +++ b/test/units/modules/network/avi/test_avi_user.py @@ -0,0 +1,101 @@ +import os +import json +from units.compat import unittest +from units.compat.mock import Mock +from units.modules.utils import set_module_args +from ansible.modules.network.avi import avi_user + +fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') +with open(fixture_path + '/avi_user.json') as json_file: + data = json.load(json_file) + + +class TestAviUser(unittest.TestCase): + + def test_create_user(self): + set_module_args({ + "avi_credentials": { + "controller": "192.0.2.13", + "username": "username", + "password": "fakepassword", + "api_version": "18.2.5" + }, + "state": "present", + "name": "testuser", + "obj_username": "testuser", + "obj_password": "test123", + "email": "test@abc.com", + "access": [ + { + "role_ref": "/api/role?name=Tenant-Admin", + "tenant_ref": "/api/tenant?name=Test-Admin", + "all_tenants": False + } + ], + "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile", + "is_active": True, + "is_superuser": True, + "default_tenant_ref": "/api/tenant?name=admin" + }) + avi_user.avi_ansible_api = Mock(return_value=data['mock_create_res']) + response = avi_user.main() + assert response['changed'] + + def test_put_on_user(self): + set_module_args({ + "avi_credentials": { + "controller": "192.0.2.13", + "username": "username", + "password": "fakepassword", + "api_version": "18.2.5" + }, + "state": "present", + "avi_api_update_method": "put", + "name": "testuser", + "obj_username": "testuser", + "obj_password": "test123", + "email": "newemail@abc.com", + "access": [{ + "role_ref": "/api/role?name=Tenant-Admin", + "tenant_ref": "/api/tenant?name=Test-Admin", + "all_tenants": False + }], + "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile", + "is_active": True, + "is_superuser": True, + "default_tenant_ref": "/api/tenant?name=admin" + }) + avi_user.avi_ansible_api = Mock(return_value=data['mock_put_res']) + response = avi_user.main() + assert response['changed'] + assert response['obj'] + assert response['old_obj'] + + def test_delete_user(self): + set_module_args({ + "avi_credentials": { + "controller": "192.0.2.13", + "username": "username", + "password": "fakepassword", + "api_version": "18.2.5" + + }, + "name": "testuser", + "obj_username": "testuser", + "obj_password": "test123", + "email": "test@abc.com", + "access": [{ + "role_ref": "/api/role?name=Tenant-Admin", + "tenant_ref": "/api/tenant?name=Test-Admin", + "all_tenants": False + }], + "user_profile_ref": "/api/useraccountprofile?name=Default-User-Account-Profile", + "is_active": True, + "is_superuser": True, + "default_tenant_ref": "/api/tenant?name=admin" + }) + avi_user.avi_ansible_api = Mock(return_value=data['mock_del_res']) + response = avi_user.main() + assert response['changed'] + assert not response['obj'] + assert response['old_obj']