Server IP : 85.214.239.14 / Your IP : 3.144.37.178 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /lib/python3/dist-packages/ansible_collections/community/sap/plugins/modules/ |
Upload File : |
#!/usr/bin/python # -*- coding: utf-8 -*- # Copyright: (c) 2021, Rainer Leber <rainerleber@gmail.com> <rainer.leber@sva.de> # 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 = r''' --- module: sap_user short_description: This module will manage a user entities in a SAP S4/HANA environment version_added: "1.0.0" description: - The M(community.sap.sap_user) module depends on C(pyrfc) Python library (version 2.4.0 and upwards). Depending on distribution you are using, you may need to install additional packages to have these available. - This module will use the following user BAPIs to manage user entities. - C(BAPI_USER_GET_DETAIL) - C(BAPI_USER_DELETE) - C(BAPI_USER_CREATE1) - C(BAPI_USER_CHANGE) - C(BAPI_USER_ACTGROUPS_ASSIGN) - C(BAPI_USER_PROFILES_ASSIGN) - C(BAPI_USER_UNLOCK) - C(BAPI_USER_LOCK) options: state: description: - The decision what to do with the user. default: 'present' choices: - 'present' - 'absent' - 'lock' - 'unlock' required: false type: str force: description: - Must be C('True') if the password or type should be overwritten. default: False required: false type: bool conn_username: description: The required username for the SAP system. required: true type: str conn_password: description: The required password for the SAP system. required: true type: str host: description: The required host for the SAP system. Can be either an FQDN or IP Address. required: true type: str sysnr: description: - The system number of the SAP system. - You must quote the value to ensure retaining the leading zeros. default: '00' type: str client: description: - The client number to connect to. - You must quote the value to ensure retaining the leading zeros. default: '000' type: str username: description: - The username. type: str required: true firstname: description: - The Firstname of the user in the SAP system. type: str required: false lastname: description: - The lastname of the user in the SAP system. type: str required: false email: description: - The email address of the user in the SAP system. type: str required: false password: description: - The password for the user in the SAP system. type: str required: false useralias: description: - The alias for the user in the SAP system. type: str required: false user_type: description: - The type for the user in the SAP system. - C('A') Dialog user, C('B') System User, C('C') Communication User, C('S') Service User, C('L') Reference User. - Must be in uppercase. type: str required: false default: 'A' choices: ['A', 'B', 'C', 'S', 'L'] company: description: - The specific company the user belongs to. - The company name must be available in the SAP system. type: str required: false profiles: description: - Assign profiles to the user. - Should be in uppercase, for example C('SAP_NEW') or C('SAP_ALL'). type: list elements: str default: [''] required: false roles: description: - Assign roles to the user. type: list elements: str default: [''] required: false requirements: - pyrfc >= 2.4.0 author: - Rainer Leber (@rainerleber) notes: - Does not support C(check_mode). ''' EXAMPLES = r''' - name: Create SAP User community.sap.sap_user: conn_username: 'DDIC' conn_password: 'Test123' host: 192.168.1.150 sysnr: '01' client: '000' state: present username: ADMIN firstname: first_admin lastname: last_admin email: admin@test.de password: Test123456 useralias: ADMIN company: DEFAULT_COMPANY roles: - "SAP_ALL" - name: Force change SAP User community.sap.sap_user: conn_username: 'DDIC' conn_password: 'Test123' host: 192.168.1.150 sysnr: '01' client: '000' state: present force: true username: ADMIN firstname: first_admin lastname: last_admin email: admin@test.de password: Test123456 useralias: ADMIN company: DEFAULT_COMPANY roles: - "SAP_ALL" - name: Delete SAP User community.sap.sap_user: conn_username: 'DDIC' conn_password: 'Test123' host: 192.168.1.150 sysnr: '01' client: '000' state: absent force: true username: ADMIN - name: Unlock SAP User community.sap.sap_user: conn_username: 'DDIC' conn_password: 'Test123' host: 192.168.1.150 sysnr: '01' client: '000' state: unlock force: true username: ADMIN ''' RETURN = r''' msg: description: A small execution description about the user action. type: str returned: always sample: 'User ADMIN created' out: description: A detailed description about the user action. type: list elements: dict returned: on success sample: [...,{ "RETURN": [ { "FIELD": "BNAME", "ID": "01", "LOG_MSG_NO": "000000", "LOG_NO": "", "MESSAGE": "User ADMIN created", "MESSAGE_V1": "ADMIN", "MESSAGE_V2": "", "MESSAGE_V3": "", "MESSAGE_V4": "", "NUMBER": "102", "PARAMETER": "", "ROW": 0, "SYSTEM": "", "TYPE": "S" } ], "SAPUSER_UUID_HIST": []}] ''' from ansible.module_utils.basic import AnsibleModule, missing_required_lib import traceback import datetime try: from pyrfc import Connection except ImportError: HAS_PYRFC_LIBRARY = False PYRFC_LIBRARY_IMPORT_ERROR = traceback.format_exc() else: HAS_PYRFC_LIBRARY = True def add_to_dict(target_dict, target_key, value): # Adds the given value to a dict as the key # check if the given key is in the given dict yet if target_key in target_dict: return False target_dict[target_key] = value return True def call_rfc_method(connection, method_name, kwargs): # PyRFC call function return connection.call(method_name, **kwargs) def build_rfc_user_params(username, firstname, lastname, email, raw_password, useralias, user_type, raw_company, user_change, force): """Creates RFC parameters for Creating users""" # define dicts in batch params = dict() address = dict() password = dict() alias = dict() logondata = dict() company = dict() # for change parameters addressx = dict() passwordx = dict() logondatax = dict() companyx = dict() # define username add_to_dict(params, 'USERNAME', username) # define Address add_to_dict(address, 'FIRSTNAME', firstname) add_to_dict(address, 'LASTNAME', lastname) add_to_dict(address, 'E_MAIL', email) # define Password add_to_dict(password, 'BAPIPWD', raw_password) # define Alias add_to_dict(alias, 'USERALIAS', useralias) # define LogonData add_to_dict(logondata, 'GLTGV', datetime.date.today()) add_to_dict(logondata, 'GLTGB', '20991231') add_to_dict(logondata, 'USTYP', user_type) # define company add_to_dict(company, 'COMPANY', raw_company) params['LOGONDATA'] = logondata params['ADDRESS'] = address params['COMPANY'] = company params['ALIAS'] = alias params['PASSWORD'] = password # add change if user exists if user_change and force: add_to_dict(addressx, 'FIRSTNAME', 'X') add_to_dict(addressx, 'LASTNAME', 'X') add_to_dict(addressx, 'E_MAIL', 'X') # define Password add_to_dict(passwordx, 'BAPIPWD', 'X') # define LogonData add_to_dict(logondatax, 'USTYP', 'X') # define company add_to_dict(companyx, 'COMPANY', 'X') params['LOGONDATAX'] = logondatax params['ADDRESSX'] = addressx params['COMPANYX'] = companyx params['PASSWORDX'] = passwordx return params def user_role_assignment_build_rfc_params(roles, username): rfc_table = [] for role_name in roles: table_row = {'AGR_NAME': role_name} add_to_dict(table_row, 'FROM_DAT', datetime.date.today()) add_to_dict(table_row, 'TO_DAT', '20991231') rfc_table.append(table_row) return { 'USERNAME': username, 'ACTIVITYGROUPS': rfc_table } def user_profile_assignment_build_rfc_params(profiles, username): rfc_table = [] for profile_name in profiles: table_row = {'BAPIPROF': profile_name} rfc_table.append(table_row) return { 'USERNAME': username, 'PROFILES': rfc_table } def check_user(user_detail): if len(user_detail['RETURN']) > 0: for sub in user_detail['RETURN']: if sub['NUMBER'] == '124': return False return True def return_analysis(raw): change = False failed = False for state in raw['RETURN']: if state['TYPE'] == "E": if state['NUMBER'] == '224' or state['NUMBER'] == '124': change = False else: failed = True if state['TYPE'] == "S": if state['NUMBER'] != '029': change = True if state['TYPE'] == "W": if state['NUMBER'] == '049' or state['NUMBER'] == '047': change = True if state['NUMBER'] == '255': change = True return [{"change": change}, {"failed": failed}] def run_module(): module = AnsibleModule( argument_spec=dict( # logical values state=dict(default='present', choices=[ 'absent', 'present', 'lock', 'unlock']), force=dict(type='bool', default=False), # values for connection conn_username=dict(type='str', required=True), conn_password=dict(type='str', required=True, no_log=True), host=dict(type='str', required=True), sysnr=dict(type='str', default="00"), client=dict(type='str', default="000"), # values for the new or existing user username=dict(type='str', required=True), firstname=dict(type='str', required=False), lastname=dict(type='str', required=False), email=dict(type='str', required=False), password=dict(type='str', required=False, no_log=True), useralias=dict(type='str', required=False), user_type=dict(default="A", choices=['A', 'B', 'C', 'S', 'L']), company=dict(type='str', required=False), # values for profile must a list # Example ["SAP_NEW", "SAP_ALL"] profiles=dict(type='list', elements='str', default=[""]), # values for roles must a list roles=dict(type='list', elements='str', default=[""]), ), supports_check_mode=False, required_if=[('state', 'present', ['useralias', 'company'])] ) result = dict(changed=False, msg='', out='') count = 0 raw = "" params = module.params state = params['state'] conn_username = (params['conn_username']).upper() conn_password = params['conn_password'] host = params['host'] sysnr = params['sysnr'] client = params['client'] username = (params['username']).upper() firstname = params['firstname'] lastname = params['lastname'] email = params['email'] password = params['password'] force = params['force'] if not params['useralias'] is None: useralias = (params['useralias']).upper() user_type = (params['user_type']).upper() company = params['company'] profiles = params['profiles'] roles = params['roles'] if not HAS_PYRFC_LIBRARY: module.fail_json( msg=missing_required_lib('pyrfc'), exception=PYRFC_LIBRARY_IMPORT_ERROR) # basic RFC connection with pyrfc try: conn = Connection(user=conn_username, passwd=conn_password, ashost=host, sysnr=sysnr, client=client) except Exception as err: result['error'] = str(err) result['msg'] = 'Something went wrong connecting to the SAP system.' module.fail_json(**result) # user details user_detail = call_rfc_method(conn, 'BAPI_USER_GET_DETAIL', {'USERNAME': username}) user_exists = check_user(user_detail) if state == "absent": if user_exists: raw = call_rfc_method(conn, 'BAPI_USER_DELETE', {'USERNAME': username}) if state == "present": user_params = build_rfc_user_params(username, firstname, lastname, email, password, useralias, user_type, company, user_exists, force) if not user_exists: raw = call_rfc_method(conn, 'BAPI_USER_CREATE1', user_params) if user_exists: # check for address changes when user exists user_no_changes = all((user_detail.get('ADDRESS')).get(k) == v for k, v in (user_params.get('ADDRESS')).items()) if not user_no_changes or force: raw = call_rfc_method(conn, 'BAPI_USER_CHANGE', user_params) call_rfc_method(conn, 'BAPI_USER_ACTGROUPS_ASSIGN', user_role_assignment_build_rfc_params(roles, username)) call_rfc_method(conn, 'BAPI_USER_PROFILES_ASSIGN', user_profile_assignment_build_rfc_params(profiles, username)) if state == "unlock": if user_exists: raw = call_rfc_method(conn, 'BAPI_USER_UNLOCK', {'USERNAME': username}) if state == "lock": if user_exists: raw = call_rfc_method(conn, 'BAPI_USER_LOCK', {'USERNAME': username}) # analyse return value if raw != '': analysed = return_analysis(raw) result['out'] = raw result['changed'] = analysed[0]['change'] for msgs in raw['RETURN']: if count > 0: result['msg'] = result['msg'] + '\n' result['msg'] = result['msg'] + msgs['MESSAGE'] count = count + 1 if analysed[1]['failed']: module.fail_json(**result) else: result['msg'] = "No changes where made." module.exit_json(**result) def main(): run_module() if __name__ == '__main__': main()